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], &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 This->num_buffer_queries = 0;
309 if (!This->stateBlock->streamIsUP)
311 WORD map = stream_info->use_map;
313 /* PreLoad all the vertex buffers. */
314 for (i = 0; map; map >>= 1, ++i)
316 struct wined3d_stream_info_element *element;
317 struct wined3d_buffer *buffer;
318 struct wined3d_event_query *query;
320 if (!(map & 1)) continue;
322 element = &stream_info->elements[i];
323 buffer = (struct wined3d_buffer *)This->stateBlock->streamSource[element->stream_idx];
324 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
326 /* If PreLoad dropped the buffer object, update the stream info. */
327 if (buffer->buffer_object != element->buffer_object)
329 element->buffer_object = 0;
330 element->data = buffer_get_sysmem(buffer) + (ptrdiff_t)element->data;
333 query = ((struct wined3d_buffer *) buffer)->query;
336 This->buffer_queries[This->num_buffer_queries++] = query;
342 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
343 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
345 const struct wined3d_format_desc *format_desc = getFormatDescEntry(strided->format, gl_info);
346 e->format_desc = format_desc;
347 e->stride = strided->dwStride;
348 e->data = strided->lpData;
350 e->buffer_object = 0;
353 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
354 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
358 memset(stream_info, 0, sizeof(*stream_info));
360 if (strided->position.lpData)
361 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
362 if (strided->normal.lpData)
363 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
364 if (strided->diffuse.lpData)
365 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
366 if (strided->specular.lpData)
367 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
369 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
371 if (strided->texCoords[i].lpData)
372 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
373 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
376 stream_info->position_transformed = strided->position_transformed;
378 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
380 if (!stream_info->elements[i].format_desc) continue;
382 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
383 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
385 stream_info->swizzle_map |= 1 << i;
387 stream_info->use_map |= 1 << i;
391 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
393 TRACE("Strided Data:\n");
394 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
395 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
396 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
405 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
406 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
407 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
408 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
411 /* Context activation is done by the caller. */
412 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
414 struct wined3d_stream_info *stream_info = &device->strided_streams;
415 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
416 BOOL vs = stateblock->vertexShader && device->vs_selected_mode != SHADER_NONE;
419 if (device->up_strided)
421 /* Note: this is a ddraw fixed-function code path. */
422 TRACE("=============================== Strided Input ================================\n");
423 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
424 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
428 TRACE("============================= Vertex Declaration =============================\n");
429 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
432 if (vs && !stream_info->position_transformed)
434 if (((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->half_float_conv_needed && !fixup)
436 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
437 device->useDrawStridedSlow = TRUE;
441 device->useDrawStridedSlow = FALSE;
446 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
447 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
448 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
450 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
452 device->useDrawStridedSlow = TRUE;
456 device->useDrawStridedSlow = FALSE;
461 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
463 IWineD3DBaseTextureImpl *texture;
464 enum WINED3DSRGB srgb;
466 if (!(texture = (IWineD3DBaseTextureImpl *)stateblock->textures[idx])) return;
467 srgb = stateblock->samplerState[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
468 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
471 void device_preload_textures(IWineD3DDeviceImpl *device)
473 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
476 if (use_vs(stateblock))
478 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
480 if (((IWineD3DBaseShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.sampler_type[i])
481 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
485 if (use_ps(stateblock))
487 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
489 if (((IWineD3DBaseShaderImpl *)stateblock->pixelShader)->baseShader.reg_maps.sampler_type[i])
490 device_preload_texture(stateblock, i);
495 WORD ffu_map = device->fixed_function_usage_map;
497 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
500 device_preload_texture(stateblock, i);
505 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
507 struct wined3d_context **new_array;
509 TRACE("Adding context %p.\n", context);
511 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
512 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
516 ERR("Failed to grow the context array.\n");
520 new_array[device->numContexts++] = context;
521 device->contexts = new_array;
525 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
527 struct wined3d_context **new_array;
531 TRACE("Removing context %p.\n", context);
533 for (i = 0; i < device->numContexts; ++i)
535 if (device->contexts[i] == context)
544 ERR("Context %p doesn't exist in context array.\n", context);
548 if (!--device->numContexts)
550 HeapFree(GetProcessHeap(), 0, device->contexts);
551 device->contexts = NULL;
555 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
556 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
559 ERR("Failed to shrink context array. Oh well.\n");
563 device->contexts = new_array;
566 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
567 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
569 if (device->onscreen_depth_stencil)
571 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
572 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN);
573 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
575 device->onscreen_depth_stencil = depth_stencil;
576 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
579 /**********************************************************
580 * IUnknown parts follows
581 **********************************************************/
583 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
587 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
588 if (IsEqualGUID(riid, &IID_IUnknown)
589 || IsEqualGUID(riid, &IID_IWineD3DBase)
590 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
591 IUnknown_AddRef(iface);
596 return E_NOINTERFACE;
599 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
601 ULONG refCount = InterlockedIncrement(&This->ref);
603 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
607 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
609 ULONG refCount = InterlockedDecrement(&This->ref);
611 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
616 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
617 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
618 This->multistate_funcs[i] = NULL;
621 /* TODO: Clean up all the surfaces and textures! */
622 /* NOTE: You must release the parent if the object was created via a callback
623 ** ***************************/
625 if (!list_empty(&This->resources))
627 IWineD3DResourceImpl *resource;
628 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
630 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
632 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
633 FIXME("Leftover resource %p with type %s (%#x).\n",
634 resource, debug_d3dresourcetype(type), type);
638 if(This->contexts) ERR("Context array not freed!\n");
639 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
640 This->haveHardwareCursor = FALSE;
642 IWineD3D_Release(This->wined3d);
643 This->wined3d = NULL;
644 HeapFree(GetProcessHeap(), 0, This);
645 TRACE("Freed device %p\n", This);
651 /**********************************************************
652 * IWineD3DDevice implementation follows
653 **********************************************************/
654 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
656 *pParent = This->parent;
657 IUnknown_AddRef(This->parent);
661 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
662 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
665 struct wined3d_buffer *object;
668 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
670 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
673 ERR("Failed to allocate memory\n");
674 return E_OUTOFMEMORY;
677 FIXME("Ignoring access flags (pool)\n");
679 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
680 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
683 WARN("Failed to initialize buffer, hr %#x.\n", hr);
684 HeapFree(GetProcessHeap(), 0, object);
687 object->desc = *desc;
689 TRACE("Created buffer %p.\n", object);
691 *buffer = (IWineD3DBuffer *)object;
696 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
697 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
698 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
700 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
701 struct wined3d_buffer *object;
704 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
705 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
707 if (Pool == WINED3DPOOL_SCRATCH)
709 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
710 * anyway, SCRATCH vertex buffers aren't usable anywhere
712 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
713 *ppVertexBuffer = NULL;
714 return WINED3DERR_INVALIDCALL;
717 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
720 ERR("Out of memory\n");
721 *ppVertexBuffer = NULL;
722 return WINED3DERR_OUTOFVIDEOMEMORY;
725 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
726 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
729 WARN("Failed to initialize buffer, hr %#x.\n", hr);
730 HeapFree(GetProcessHeap(), 0, object);
734 TRACE("Created buffer %p.\n", object);
735 *ppVertexBuffer = (IWineD3DBuffer *)object;
740 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
741 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
742 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
745 struct wined3d_buffer *object;
748 TRACE("(%p) Creating index buffer\n", This);
750 /* Allocate the storage for the device */
751 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
754 ERR("Out of memory\n");
755 *ppIndexBuffer = NULL;
756 return WINED3DERR_OUTOFVIDEOMEMORY;
759 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
760 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
764 WARN("Failed to initialize buffer, hr %#x\n", hr);
765 HeapFree(GetProcessHeap(), 0, object);
769 TRACE("Created buffer %p.\n", object);
771 *ppIndexBuffer = (IWineD3DBuffer *) object;
776 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
777 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
780 IWineD3DStateBlockImpl *object;
783 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
786 ERR("Failed to allocate stateblock memory.\n");
787 return E_OUTOFMEMORY;
790 hr = stateblock_init(object, This, type);
793 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
794 HeapFree(GetProcessHeap(), 0, object);
798 TRACE("Created stateblock %p.\n", object);
799 *stateblock = (IWineD3DStateBlock *)object;
804 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
805 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
806 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
807 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
810 IWineD3DSurfaceImpl *object;
813 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
814 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
815 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
816 ppSurface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
817 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
819 if (Impl == SURFACE_OPENGL && !This->adapter)
821 ERR("OpenGL surfaces are not available without OpenGL.\n");
822 return WINED3DERR_NOTAVAILABLE;
825 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
828 ERR("Failed to allocate surface memory.\n");
829 return WINED3DERR_OUTOFVIDEOMEMORY;
832 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
833 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
836 WARN("Failed to initialize surface, returning %#x.\n", hr);
837 HeapFree(GetProcessHeap(), 0, object);
841 TRACE("(%p) : Created surface %p\n", This, object);
843 *ppSurface = (IWineD3DSurface *)object;
848 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
849 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
851 struct wined3d_rendertarget_view *object;
853 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
854 iface, resource, parent, rendertarget_view);
856 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
859 ERR("Failed to allocate memory\n");
860 return E_OUTOFMEMORY;
863 wined3d_rendertarget_view_init(object, resource, parent);
865 TRACE("Created render target view %p.\n", object);
866 *rendertarget_view = (IWineD3DRendertargetView *)object;
871 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
872 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
873 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
876 IWineD3DTextureImpl *object;
879 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
880 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
881 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
883 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
886 ERR("Out of memory\n");
888 return WINED3DERR_OUTOFVIDEOMEMORY;
891 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
894 WARN("Failed to initialize texture, returning %#x\n", hr);
895 HeapFree(GetProcessHeap(), 0, object);
900 *ppTexture = (IWineD3DTexture *)object;
902 TRACE("(%p) : Created texture %p\n", This, object);
907 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
908 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
909 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
912 IWineD3DVolumeTextureImpl *object;
915 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
916 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
918 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
921 ERR("Out of memory\n");
922 *ppVolumeTexture = NULL;
923 return WINED3DERR_OUTOFVIDEOMEMORY;
926 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
929 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
930 HeapFree(GetProcessHeap(), 0, object);
931 *ppVolumeTexture = NULL;
935 TRACE("(%p) : Created volume texture %p.\n", This, object);
936 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
941 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
942 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
943 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
946 IWineD3DVolumeImpl *object;
949 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
950 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
952 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
955 ERR("Out of memory\n");
957 return WINED3DERR_OUTOFVIDEOMEMORY;
960 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
963 WARN("Failed to initialize volume, returning %#x.\n", hr);
964 HeapFree(GetProcessHeap(), 0, object);
968 TRACE("(%p) : Created volume %p.\n", This, object);
969 *ppVolume = (IWineD3DVolume *)object;
974 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
975 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
976 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
979 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
982 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
985 ERR("Out of memory\n");
986 *ppCubeTexture = NULL;
987 return WINED3DERR_OUTOFVIDEOMEMORY;
990 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
993 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
994 HeapFree(GetProcessHeap(), 0, object);
995 *ppCubeTexture = NULL;
999 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1000 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1005 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1006 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
1008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1009 IWineD3DQueryImpl *object;
1012 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
1014 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1017 ERR("Failed to allocate query memory.\n");
1018 return E_OUTOFMEMORY;
1021 hr = query_init(object, This, type, parent);
1024 WARN("Failed to initialize query, hr %#x.\n", hr);
1025 HeapFree(GetProcessHeap(), 0, object);
1029 TRACE("Created query %p.\n", object);
1030 *query = (IWineD3DQuery *)object;
1035 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1036 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
1037 IUnknown *parent, WINED3DSURFTYPE surface_type)
1039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1040 IWineD3DSwapChainImpl *object;
1043 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1044 iface, present_parameters, swapchain, parent, surface_type);
1046 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1049 ERR("Failed to allocate swapchain memory.\n");
1050 return E_OUTOFMEMORY;
1053 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1056 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1057 HeapFree(GetProcessHeap(), 0, object);
1061 TRACE("Created swapchain %p.\n", object);
1062 *swapchain = (IWineD3DSwapChain *)object;
1067 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1068 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1070 TRACE("(%p)\n", This);
1072 return This->NumberOfSwapChains;
1075 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1077 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1079 if(iSwapChain < This->NumberOfSwapChains) {
1080 *pSwapChain = This->swapchains[iSwapChain];
1081 IWineD3DSwapChain_AddRef(*pSwapChain);
1082 TRACE("(%p) returning %p\n", This, *pSwapChain);
1085 TRACE("Swapchain out of range\n");
1087 return WINED3DERR_INVALIDCALL;
1091 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1092 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1093 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1096 IWineD3DVertexDeclarationImpl *object = NULL;
1099 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1100 iface, declaration, parent, elements, element_count);
1102 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1105 ERR("Failed to allocate vertex declaration memory.\n");
1106 return E_OUTOFMEMORY;
1109 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1112 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1113 HeapFree(GetProcessHeap(), 0, object);
1117 TRACE("Created vertex declaration %p.\n", object);
1118 *declaration = (IWineD3DVertexDeclaration *)object;
1123 struct wined3d_fvf_convert_state
1125 const struct wined3d_gl_info *gl_info;
1126 WINED3DVERTEXELEMENT *elements;
1131 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1132 WINED3DFORMAT format, WINED3DDECLUSAGE usage, UINT usage_idx)
1134 WINED3DVERTEXELEMENT *elements = state->elements;
1135 const struct wined3d_format_desc *format_desc;
1136 UINT offset = state->offset;
1137 UINT idx = state->idx;
1139 elements[idx].format = format;
1140 elements[idx].input_slot = 0;
1141 elements[idx].offset = offset;
1142 elements[idx].output_slot = 0;
1143 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1144 elements[idx].usage = usage;
1145 elements[idx].usage_idx = usage_idx;
1147 format_desc = getFormatDescEntry(format, state->gl_info);
1148 state->offset += format_desc->component_count * format_desc->component_size;
1152 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1153 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1155 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1156 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1157 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1158 BOOL has_blend_idx = has_blend &&
1159 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1160 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1161 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1162 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1163 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1164 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1165 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1167 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1168 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1169 struct wined3d_fvf_convert_state state;
1172 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1173 if (has_blend_idx) num_blends--;
1175 /* Compute declaration size */
1176 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1177 has_psize + has_diffuse + has_specular + num_textures;
1179 state.gl_info = gl_info;
1180 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1181 if (!state.elements) return ~0U;
1187 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1188 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1189 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1190 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1192 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1195 if (has_blend && (num_blends > 0))
1197 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1198 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1204 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1207 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1210 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1213 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1216 ERR("Unexpected amount of blend values: %u\n", num_blends);
1223 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1224 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1225 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1226 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1227 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1229 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1232 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1233 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1234 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1235 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1237 for (idx = 0; idx < num_textures; ++idx)
1239 switch ((texcoords >> (idx * 2)) & 0x03)
1241 case WINED3DFVF_TEXTUREFORMAT1:
1242 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1244 case WINED3DFVF_TEXTUREFORMAT2:
1245 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1247 case WINED3DFVF_TEXTUREFORMAT3:
1248 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1250 case WINED3DFVF_TEXTUREFORMAT4:
1251 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1256 *ppVertexElements = state.elements;
1260 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1261 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1262 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1265 WINED3DVERTEXELEMENT *elements;
1269 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1271 size = ConvertFvfToDeclaration(This, fvf, &elements);
1272 if (size == ~0U) return E_OUTOFMEMORY;
1274 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1275 HeapFree(GetProcessHeap(), 0, elements);
1279 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1280 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1281 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1282 const struct wined3d_parent_ops *parent_ops)
1284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1285 IWineD3DVertexShaderImpl *object;
1288 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1291 ERR("Failed to allocate shader memory.\n");
1292 return E_OUTOFMEMORY;
1295 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1298 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1299 HeapFree(GetProcessHeap(), 0, object);
1303 TRACE("Created vertex shader %p.\n", object);
1304 *ppVertexShader = (IWineD3DVertexShader *)object;
1309 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1310 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1311 IWineD3DGeometryShader **shader, IUnknown *parent,
1312 const struct wined3d_parent_ops *parent_ops)
1314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1315 struct wined3d_geometryshader *object;
1318 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1321 ERR("Failed to allocate shader memory.\n");
1322 return E_OUTOFMEMORY;
1325 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1328 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1329 HeapFree(GetProcessHeap(), 0, object);
1333 TRACE("Created geometry shader %p.\n", object);
1334 *shader = (IWineD3DGeometryShader *)object;
1339 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1340 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1341 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1342 const struct wined3d_parent_ops *parent_ops)
1344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1345 IWineD3DPixelShaderImpl *object;
1348 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1351 ERR("Failed to allocate shader memory.\n");
1352 return E_OUTOFMEMORY;
1355 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1358 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1359 HeapFree(GetProcessHeap(), 0, object);
1363 TRACE("Created pixel shader %p.\n", object);
1364 *ppPixelShader = (IWineD3DPixelShader *)object;
1369 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1370 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1373 IWineD3DPaletteImpl *object;
1376 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1377 iface, Flags, PalEnt, Palette, Parent);
1379 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1382 ERR("Failed to allocate palette memory.\n");
1383 return E_OUTOFMEMORY;
1386 hr = wined3d_palette_init(object, This, Flags, PalEnt, Parent);
1389 WARN("Failed to initialize palette, hr %#x.\n", hr);
1390 HeapFree(GetProcessHeap(), 0, object);
1394 TRACE("Created palette %p.\n", object);
1395 *Palette = (IWineD3DPalette *)object;
1400 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1404 HDC dcb = NULL, dcs = NULL;
1405 WINEDDCOLORKEY colorkey;
1407 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1410 GetObjectA(hbm, sizeof(BITMAP), &bm);
1411 dcb = CreateCompatibleDC(NULL);
1413 SelectObject(dcb, hbm);
1417 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1418 * couldn't be loaded
1420 memset(&bm, 0, sizeof(bm));
1425 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1426 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1427 NULL, &wined3d_null_parent_ops);
1429 ERR("Wine logo requested, but failed to create surface\n");
1434 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1435 if(FAILED(hr)) goto out;
1436 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1437 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1439 colorkey.dwColorSpaceLowValue = 0;
1440 colorkey.dwColorSpaceHighValue = 0;
1441 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1443 /* Fill the surface with a white color to show that wined3d is there */
1444 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1448 if (dcb) DeleteDC(dcb);
1449 if (hbm) DeleteObject(hbm);
1452 /* Context activation is done by the caller. */
1453 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1455 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1457 /* Under DirectX you can have texture stage operations even if no texture is
1458 bound, whereas opengl will only do texture operations when a valid texture is
1459 bound. We emulate this by creating dummy textures and binding them to each
1460 texture stage, but disable all stages by default. Hence if a stage is enabled
1461 then the default texture will kick in until replaced by a SetTexture call */
1464 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1466 /* The dummy texture does not have client storage backing */
1467 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1468 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1471 for (i = 0; i < gl_info->limits.textures; ++i)
1473 GLubyte white = 255;
1475 /* Make appropriate texture active */
1476 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1477 checkGLcall("glActiveTextureARB");
1479 /* Generate an opengl texture name */
1480 glGenTextures(1, &This->dummyTextureName[i]);
1481 checkGLcall("glGenTextures");
1482 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1484 /* Generate a dummy 2d texture (not using 1d because they cause many
1485 * DRI drivers fall back to sw) */
1486 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1487 checkGLcall("glBindTexture");
1489 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1490 checkGLcall("glTexImage2D");
1493 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1495 /* Reenable because if supported it is enabled by default */
1496 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1497 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1503 /* Context activation is done by the caller. */
1504 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1507 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1508 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1511 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1514 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1516 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1518 if (!wined3d_register_window(window, device))
1520 ERR("Failed to register window %p.\n", window);
1524 device->focus_window = window;
1525 SetForegroundWindow(window);
1530 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1532 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1534 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1535 device->focus_window = NULL;
1538 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1539 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1542 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1543 IWineD3DSwapChainImpl *swapchain = NULL;
1544 struct wined3d_context *context;
1549 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1551 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1552 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1554 TRACE("(%p) : Creating stateblock\n", This);
1555 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1556 hr = IWineD3DDevice_CreateStateBlock(iface,
1558 (IWineD3DStateBlock **)&This->stateBlock,
1560 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1561 WARN("Failed to create stateblock\n");
1564 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1565 This->updateStateBlock = This->stateBlock;
1566 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1568 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1569 sizeof(*This->render_targets) * gl_info->limits.buffers);
1570 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1571 sizeof(GLenum) * gl_info->limits.buffers);
1573 This->NumberOfPalettes = 1;
1574 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1575 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1576 ERR("Out of memory!\n");
1580 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1581 if(!This->palettes[0]) {
1582 ERR("Out of memory!\n");
1586 for (i = 0; i < 256; ++i) {
1587 This->palettes[0][i].peRed = 0xFF;
1588 This->palettes[0][i].peGreen = 0xFF;
1589 This->palettes[0][i].peBlue = 0xFF;
1590 This->palettes[0][i].peFlags = 0xFF;
1592 This->currentPalette = 0;
1594 /* Initialize the texture unit mapping to a 1:1 mapping */
1595 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1597 if (state < gl_info->limits.fragment_samplers)
1599 This->texUnitMap[state] = state;
1600 This->rev_tex_unit_map[state] = state;
1602 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1603 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1607 /* Setup the implicit swapchain. This also initializes a context. */
1608 TRACE("Creating implicit swapchain\n");
1609 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1610 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1613 WARN("Failed to create implicit swapchain\n");
1617 This->NumberOfSwapChains = 1;
1618 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1619 if(!This->swapchains) {
1620 ERR("Out of memory!\n");
1623 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1625 if (swapchain->back_buffers && swapchain->back_buffers[0])
1627 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1628 This->render_targets[0] = swapchain->back_buffers[0];
1632 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1633 This->render_targets[0] = swapchain->front_buffer;
1635 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1637 /* Depth Stencil support */
1638 This->depth_stencil = This->auto_depth_stencil;
1639 if (This->depth_stencil)
1640 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1642 hr = This->shader_backend->shader_alloc_private(iface);
1644 TRACE("Shader private data couldn't be allocated\n");
1647 hr = This->frag_pipe->alloc_private(iface);
1649 TRACE("Fragment pipeline private data couldn't be allocated\n");
1652 hr = This->blitter->alloc_private(iface);
1654 TRACE("Blitter private data couldn't be allocated\n");
1658 /* Set up some starting GL setup */
1660 /* Setup all the devices defaults */
1661 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1663 context = context_acquire(This, swapchain->front_buffer, CTXUSAGE_RESOURCELOAD);
1665 create_dummy_textures(This);
1669 /* Initialize the current view state */
1670 This->view_ident = 1;
1671 This->contexts[0]->last_was_rhw = 0;
1672 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1673 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1675 switch(wined3d_settings.offscreen_rendering_mode) {
1677 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1680 case ORM_BACKBUFFER:
1682 if (context_get_current()->aux_buffers > 0)
1684 TRACE("Using auxilliary buffer for offscreen rendering\n");
1685 This->offscreenBuffer = GL_AUX0;
1687 TRACE("Using back buffer for offscreen rendering\n");
1688 This->offscreenBuffer = GL_BACK;
1693 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1696 context_release(context);
1698 /* Clear the screen */
1699 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1700 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1703 This->d3d_initialized = TRUE;
1705 if(wined3d_settings.logo) {
1706 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1708 This->highest_dirty_ps_const = 0;
1709 This->highest_dirty_vs_const = 0;
1713 HeapFree(GetProcessHeap(), 0, This->render_targets);
1714 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1715 HeapFree(GetProcessHeap(), 0, This->swapchains);
1716 This->NumberOfSwapChains = 0;
1717 if(This->palettes) {
1718 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1719 HeapFree(GetProcessHeap(), 0, This->palettes);
1721 This->NumberOfPalettes = 0;
1723 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1725 if(This->stateBlock) {
1726 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1727 This->stateBlock = NULL;
1729 if (This->blit_priv) {
1730 This->blitter->free_private(iface);
1732 if (This->fragment_priv) {
1733 This->frag_pipe->free_private(iface);
1735 if (This->shader_priv) {
1736 This->shader_backend->shader_free_private(iface);
1741 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1742 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1745 IWineD3DSwapChainImpl *swapchain = NULL;
1748 /* Setup the implicit swapchain */
1749 TRACE("Creating implicit swapchain\n");
1750 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1751 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1754 WARN("Failed to create implicit swapchain\n");
1758 This->NumberOfSwapChains = 1;
1759 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1760 if(!This->swapchains) {
1761 ERR("Out of memory!\n");
1764 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1768 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1772 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1774 IWineD3DResource_UnLoad(resource);
1775 IWineD3DResource_Release(resource);
1779 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1780 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1783 const struct wined3d_gl_info *gl_info;
1784 struct wined3d_context *context;
1787 TRACE("(%p)\n", This);
1789 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1791 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1792 * it was created. Thus make sure a context is active for the glDelete* calls
1794 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
1795 gl_info = context->gl_info;
1797 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1799 /* Unload resources */
1800 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1802 TRACE("Deleting high order patches\n");
1803 for(i = 0; i < PATCHMAP_SIZE; i++) {
1804 struct list *e1, *e2;
1805 struct WineD3DRectPatch *patch;
1806 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1807 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1808 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1812 /* Delete the mouse cursor texture */
1813 if(This->cursorTexture) {
1815 glDeleteTextures(1, &This->cursorTexture);
1817 This->cursorTexture = 0;
1820 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1821 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1823 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1824 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1827 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1828 * private data, it might contain opengl pointers
1830 if(This->depth_blt_texture) {
1832 glDeleteTextures(1, &This->depth_blt_texture);
1834 This->depth_blt_texture = 0;
1836 if (This->depth_blt_rb) {
1838 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1840 This->depth_blt_rb = 0;
1841 This->depth_blt_rb_w = 0;
1842 This->depth_blt_rb_h = 0;
1845 /* Release the update stateblock */
1846 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1847 if(This->updateStateBlock != This->stateBlock)
1848 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1850 This->updateStateBlock = NULL;
1852 { /* because were not doing proper internal refcounts releasing the primary state block
1853 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1854 to set this->stateBlock = NULL; first */
1855 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1856 This->stateBlock = NULL;
1858 /* Release the stateblock */
1859 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1860 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1864 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1865 This->blitter->free_private(iface);
1866 This->frag_pipe->free_private(iface);
1867 This->shader_backend->shader_free_private(iface);
1869 /* Release the buffers (with sanity checks)*/
1870 if (This->onscreen_depth_stencil)
1872 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
1873 This->onscreen_depth_stencil = NULL;
1876 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
1877 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
1879 if (This->auto_depth_stencil != This->depth_stencil)
1880 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
1882 This->depth_stencil = NULL;
1884 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1885 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
1887 TRACE("Setting rendertarget to NULL\n");
1888 This->render_targets[0] = NULL;
1890 if (This->auto_depth_stencil)
1892 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
1894 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1896 This->auto_depth_stencil = NULL;
1899 context_release(context);
1901 for(i=0; i < This->NumberOfSwapChains; i++) {
1902 TRACE("Releasing the implicit swapchain %d\n", i);
1903 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1904 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1908 HeapFree(GetProcessHeap(), 0, This->swapchains);
1909 This->swapchains = NULL;
1910 This->NumberOfSwapChains = 0;
1912 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1913 HeapFree(GetProcessHeap(), 0, This->palettes);
1914 This->palettes = NULL;
1915 This->NumberOfPalettes = 0;
1917 HeapFree(GetProcessHeap(), 0, This->render_targets);
1918 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1919 This->render_targets = NULL;
1920 This->draw_buffers = NULL;
1922 This->d3d_initialized = FALSE;
1927 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1931 for(i=0; i < This->NumberOfSwapChains; i++) {
1932 TRACE("Releasing the implicit swapchain %d\n", i);
1933 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1934 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1938 HeapFree(GetProcessHeap(), 0, This->swapchains);
1939 This->swapchains = NULL;
1940 This->NumberOfSwapChains = 0;
1944 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1945 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1946 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1948 * There is no way to deactivate thread safety once it is enabled.
1950 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1953 /*For now just store the flag(needed in case of ddraw) */
1954 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1957 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1958 const WINED3DDISPLAYMODE* pMode) {
1960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1961 const struct wined3d_format_desc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1965 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1967 /* Resize the screen even without a window:
1968 * The app could have unset it with SetCooperativeLevel, but not called
1969 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1970 * but we don't have any hwnd
1973 memset(&devmode, 0, sizeof(devmode));
1974 devmode.dmSize = sizeof(devmode);
1975 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1976 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1977 devmode.dmPelsWidth = pMode->Width;
1978 devmode.dmPelsHeight = pMode->Height;
1980 devmode.dmDisplayFrequency = pMode->RefreshRate;
1981 if (pMode->RefreshRate != 0) {
1982 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1985 /* Only change the mode if necessary */
1986 if( (This->ddraw_width == pMode->Width) &&
1987 (This->ddraw_height == pMode->Height) &&
1988 (This->ddraw_format == pMode->Format) &&
1989 (pMode->RefreshRate == 0) ) {
1993 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1994 if (ret != DISP_CHANGE_SUCCESSFUL) {
1995 if(devmode.dmDisplayFrequency != 0) {
1996 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1997 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1998 devmode.dmDisplayFrequency = 0;
1999 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2001 if(ret != DISP_CHANGE_SUCCESSFUL) {
2002 return WINED3DERR_NOTAVAILABLE;
2006 /* Store the new values */
2007 This->ddraw_width = pMode->Width;
2008 This->ddraw_height = pMode->Height;
2009 This->ddraw_format = pMode->Format;
2011 /* And finally clip mouse to our screen */
2012 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2013 ClipCursor(&clip_rc);
2018 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2020 *ppD3D = This->wined3d;
2021 TRACE("Returning %p.\n", *ppD3D);
2022 IWineD3D_AddRef(*ppD3D);
2026 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2029 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2030 (This->adapter->TextureRam/(1024*1024)),
2031 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2032 /* return simulated texture memory left */
2033 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2037 * Get / Set Stream Source
2039 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2040 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2043 IWineD3DBuffer *oldSrc;
2045 if (StreamNumber >= MAX_STREAMS) {
2046 WARN("Stream out of range %d\n", StreamNumber);
2047 return WINED3DERR_INVALIDCALL;
2048 } else if(OffsetInBytes & 0x3) {
2049 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2050 return WINED3DERR_INVALIDCALL;
2053 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2054 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2056 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2058 if(oldSrc == pStreamData &&
2059 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2060 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2061 TRACE("Application is setting the old values over, nothing to do\n");
2065 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2067 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2068 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2071 /* Handle recording of state blocks */
2072 if (This->isRecordingState) {
2073 TRACE("Recording... not performing anything\n");
2074 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2075 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2079 if (pStreamData != NULL) {
2080 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2081 IWineD3DBuffer_AddRef(pStreamData);
2083 if (oldSrc != NULL) {
2084 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2085 IWineD3DBuffer_Release(oldSrc);
2088 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2093 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2094 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2098 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2099 This->stateBlock->streamSource[StreamNumber],
2100 This->stateBlock->streamOffset[StreamNumber],
2101 This->stateBlock->streamStride[StreamNumber]);
2103 if (StreamNumber >= MAX_STREAMS) {
2104 WARN("Stream out of range %d\n", StreamNumber);
2105 return WINED3DERR_INVALIDCALL;
2107 *pStream = This->stateBlock->streamSource[StreamNumber];
2108 *pStride = This->stateBlock->streamStride[StreamNumber];
2110 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2113 if (*pStream != NULL) {
2114 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2119 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2121 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2122 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2124 /* Verify input at least in d3d9 this is invalid*/
2125 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2126 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2127 return WINED3DERR_INVALIDCALL;
2129 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2130 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2131 return WINED3DERR_INVALIDCALL;
2134 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2135 return WINED3DERR_INVALIDCALL;
2138 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2139 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2141 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2142 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2144 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2145 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2146 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2152 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2155 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2156 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2158 TRACE("(%p) : returning %d\n", This, *Divider);
2164 * Get / Set & Multiply Transform
2166 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2169 /* Most of this routine, comments included copied from ddraw tree initially: */
2170 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2172 /* Handle recording of state blocks */
2173 if (This->isRecordingState) {
2174 TRACE("Recording... not performing anything\n");
2175 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2176 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2181 * If the new matrix is the same as the current one,
2182 * we cut off any further processing. this seems to be a reasonable
2183 * optimization because as was noticed, some apps (warcraft3 for example)
2184 * tend towards setting the same matrix repeatedly for some reason.
2186 * From here on we assume that the new matrix is different, wherever it matters.
2188 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2189 TRACE("The app is setting the same matrix over again\n");
2192 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2196 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2197 where ViewMat = Camera space, WorldMat = world space.
2199 In OpenGL, camera and world space is combined into GL_MODELVIEW
2200 matrix. The Projection matrix stay projection matrix.
2203 /* Capture the times we can just ignore the change for now */
2204 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2205 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2206 /* Handled by the state manager */
2209 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2213 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2214 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2215 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2216 *pMatrix = This->stateBlock->transforms[State];
2220 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2221 const WINED3DMATRIX *mat = NULL;
2224 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2225 * below means it will be recorded in a state block change, but it
2226 * works regardless where it is recorded.
2227 * If this is found to be wrong, change to StateBlock.
2229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2230 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2232 if (State <= HIGHEST_TRANSFORMSTATE)
2234 mat = &This->updateStateBlock->transforms[State];
2236 FIXME("Unhandled transform state!!\n");
2239 multiply_matrix(&temp, mat, pMatrix);
2241 /* Apply change via set transform - will reapply to eg. lights this way */
2242 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2248 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2249 you can reference any indexes you want as long as that number max are enabled at any
2250 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2251 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2252 but when recording, just build a chain pretty much of commands to be replayed. */
2254 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2256 struct wined3d_light_info *object = NULL;
2257 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2261 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2263 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2267 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2268 return WINED3DERR_INVALIDCALL;
2271 switch(pLight->Type) {
2272 case WINED3DLIGHT_POINT:
2273 case WINED3DLIGHT_SPOT:
2274 case WINED3DLIGHT_PARALLELPOINT:
2275 case WINED3DLIGHT_GLSPOT:
2276 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2279 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2281 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2282 return WINED3DERR_INVALIDCALL;
2286 case WINED3DLIGHT_DIRECTIONAL:
2287 /* Ignores attenuation */
2291 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2292 return WINED3DERR_INVALIDCALL;
2295 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2297 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2298 if(object->OriginalIndex == Index) break;
2303 TRACE("Adding new light\n");
2304 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2306 ERR("Out of memory error when allocating a light\n");
2307 return E_OUTOFMEMORY;
2309 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2310 object->glIndex = -1;
2311 object->OriginalIndex = Index;
2314 /* Initialize the object */
2315 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,
2316 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2317 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2318 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2319 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2320 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2321 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2323 /* Save away the information */
2324 object->OriginalParms = *pLight;
2326 switch (pLight->Type) {
2327 case WINED3DLIGHT_POINT:
2329 object->lightPosn[0] = pLight->Position.x;
2330 object->lightPosn[1] = pLight->Position.y;
2331 object->lightPosn[2] = pLight->Position.z;
2332 object->lightPosn[3] = 1.0f;
2333 object->cutoff = 180.0f;
2337 case WINED3DLIGHT_DIRECTIONAL:
2339 object->lightPosn[0] = -pLight->Direction.x;
2340 object->lightPosn[1] = -pLight->Direction.y;
2341 object->lightPosn[2] = -pLight->Direction.z;
2342 object->lightPosn[3] = 0.0f;
2343 object->exponent = 0.0f;
2344 object->cutoff = 180.0f;
2347 case WINED3DLIGHT_SPOT:
2349 object->lightPosn[0] = pLight->Position.x;
2350 object->lightPosn[1] = pLight->Position.y;
2351 object->lightPosn[2] = pLight->Position.z;
2352 object->lightPosn[3] = 1.0f;
2355 object->lightDirn[0] = pLight->Direction.x;
2356 object->lightDirn[1] = pLight->Direction.y;
2357 object->lightDirn[2] = pLight->Direction.z;
2358 object->lightDirn[3] = 1.0f;
2361 * opengl-ish and d3d-ish spot lights use too different models for the
2362 * light "intensity" as a function of the angle towards the main light direction,
2363 * so we only can approximate very roughly.
2364 * however spot lights are rather rarely used in games (if ever used at all).
2365 * furthermore if still used, probably nobody pays attention to such details.
2367 if (pLight->Falloff == 0) {
2368 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2369 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2370 * will always be 1.0 for both of them, and we don't have to care for the
2371 * rest of the rather complex calculation
2373 object->exponent = 0.0f;
2375 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2376 if (rho < 0.0001f) rho = 0.0001f;
2377 object->exponent = -0.3f/logf(cosf(rho/2));
2379 if (object->exponent > 128.0f)
2381 object->exponent = 128.0f;
2383 object->cutoff = pLight->Phi*90/M_PI;
2389 FIXME("Unrecognized light type %d\n", pLight->Type);
2392 /* Update the live definitions if the light is currently assigned a glIndex */
2393 if (object->glIndex != -1 && !This->isRecordingState) {
2394 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2399 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2401 struct wined3d_light_info *lightInfo = NULL;
2402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2403 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2405 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2407 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2409 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2410 if(lightInfo->OriginalIndex == Index) break;
2414 if (lightInfo == NULL) {
2415 TRACE("Light information requested but light not defined\n");
2416 return WINED3DERR_INVALIDCALL;
2419 *pLight = lightInfo->OriginalParms;
2424 * Get / Set Light Enable
2425 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2427 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2429 struct wined3d_light_info *lightInfo = NULL;
2430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2431 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2433 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2435 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2437 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2438 if(lightInfo->OriginalIndex == Index) break;
2441 TRACE("Found light: %p\n", lightInfo);
2443 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2444 if (lightInfo == NULL) {
2446 TRACE("Light enabled requested but light not defined, so defining one!\n");
2447 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2449 /* Search for it again! Should be fairly quick as near head of list */
2450 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2452 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2453 if(lightInfo->OriginalIndex == Index) break;
2456 if (lightInfo == NULL) {
2457 FIXME("Adding default lights has failed dismally\n");
2458 return WINED3DERR_INVALIDCALL;
2463 if(lightInfo->glIndex != -1) {
2464 if(!This->isRecordingState) {
2465 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2468 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2469 lightInfo->glIndex = -1;
2471 TRACE("Light already disabled, nothing to do\n");
2473 lightInfo->enabled = FALSE;
2475 lightInfo->enabled = TRUE;
2476 if (lightInfo->glIndex != -1) {
2478 TRACE("Nothing to do as light was enabled\n");
2481 /* Find a free gl light */
2482 for(i = 0; i < This->maxConcurrentLights; i++) {
2483 if(This->updateStateBlock->activeLights[i] == NULL) {
2484 This->updateStateBlock->activeLights[i] = lightInfo;
2485 lightInfo->glIndex = i;
2489 if(lightInfo->glIndex == -1) {
2490 /* Our tests show that Windows returns D3D_OK in this situation, even with
2491 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2492 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2493 * as well for those lights.
2495 * TODO: Test how this affects rendering
2497 WARN("Too many concurrently active lights\n");
2501 /* i == lightInfo->glIndex */
2502 if(!This->isRecordingState) {
2503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2511 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2513 struct wined3d_light_info *lightInfo = NULL;
2514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2516 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2517 TRACE("(%p) : for idx(%d)\n", This, Index);
2519 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2521 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2522 if(lightInfo->OriginalIndex == Index) break;
2526 if (lightInfo == NULL) {
2527 TRACE("Light enabled state requested but light not defined\n");
2528 return WINED3DERR_INVALIDCALL;
2530 /* true is 128 according to SetLightEnable */
2531 *pEnable = lightInfo->enabled ? 128 : 0;
2536 * Get / Set Clip Planes
2538 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2540 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2542 /* Validate Index */
2543 if (Index >= This->adapter->gl_info.limits.clipplanes)
2545 TRACE("Application has requested clipplane this device doesn't support\n");
2546 return WINED3DERR_INVALIDCALL;
2549 This->updateStateBlock->changed.clipplane |= 1 << Index;
2551 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2552 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2553 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2554 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2555 TRACE("Application is setting old values over, nothing to do\n");
2559 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2560 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2561 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2562 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2564 /* Handle recording of state blocks */
2565 if (This->isRecordingState) {
2566 TRACE("Recording... not performing anything\n");
2570 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2575 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2577 TRACE("(%p) : for idx %d\n", This, Index);
2579 /* Validate Index */
2580 if (Index >= This->adapter->gl_info.limits.clipplanes)
2582 TRACE("Application has requested clipplane this device doesn't support\n");
2583 return WINED3DERR_INVALIDCALL;
2586 pPlane[0] = This->stateBlock->clipplane[Index][0];
2587 pPlane[1] = This->stateBlock->clipplane[Index][1];
2588 pPlane[2] = This->stateBlock->clipplane[Index][2];
2589 pPlane[3] = This->stateBlock->clipplane[Index][3];
2594 * Get / Set Clip Plane Status
2595 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2597 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2599 FIXME("(%p) : stub\n", This);
2600 if (NULL == pClipStatus) {
2601 return WINED3DERR_INVALIDCALL;
2603 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2604 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2608 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2610 FIXME("(%p) : stub\n", This);
2611 if (NULL == pClipStatus) {
2612 return WINED3DERR_INVALIDCALL;
2614 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2615 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2620 * Get / Set Material
2622 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2625 This->updateStateBlock->changed.material = TRUE;
2626 This->updateStateBlock->material = *pMaterial;
2628 /* Handle recording of state blocks */
2629 if (This->isRecordingState) {
2630 TRACE("Recording... not performing anything\n");
2634 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2638 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2640 *pMaterial = This->updateStateBlock->material;
2641 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2642 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2643 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2644 pMaterial->Ambient.b, pMaterial->Ambient.a);
2645 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2646 pMaterial->Specular.b, pMaterial->Specular.a);
2647 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2648 pMaterial->Emissive.b, pMaterial->Emissive.a);
2649 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2657 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2658 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2661 IWineD3DBuffer *oldIdxs;
2663 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2664 oldIdxs = This->updateStateBlock->pIndexData;
2666 This->updateStateBlock->changed.indices = TRUE;
2667 This->updateStateBlock->pIndexData = pIndexData;
2668 This->updateStateBlock->IndexFmt = fmt;
2670 /* Handle recording of state blocks */
2671 if (This->isRecordingState) {
2672 TRACE("Recording... not performing anything\n");
2673 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2674 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2678 if(oldIdxs != pIndexData) {
2679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2681 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2682 IWineD3DBuffer_AddRef(pIndexData);
2685 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2686 IWineD3DBuffer_Release(oldIdxs);
2693 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2697 *ppIndexData = This->stateBlock->pIndexData;
2699 /* up ref count on ppindexdata */
2701 IWineD3DBuffer_AddRef(*ppIndexData);
2702 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2704 TRACE("(%p) No index data set\n", This);
2706 TRACE("Returning %p\n", *ppIndexData);
2711 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2712 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2714 TRACE("(%p)->(%d)\n", This, BaseIndex);
2716 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2717 TRACE("Application is setting the old value over, nothing to do\n");
2721 This->updateStateBlock->baseVertexIndex = BaseIndex;
2723 if (This->isRecordingState) {
2724 TRACE("Recording... not performing anything\n");
2727 /* The base vertex index affects the stream sources */
2728 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2732 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2734 TRACE("(%p) : base_index %p\n", This, base_index);
2736 *base_index = This->stateBlock->baseVertexIndex;
2738 TRACE("Returning %u\n", *base_index);
2744 * Get / Set Viewports
2746 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2749 TRACE("(%p)\n", This);
2750 This->updateStateBlock->changed.viewport = TRUE;
2751 This->updateStateBlock->viewport = *pViewport;
2753 /* Handle recording of state blocks */
2754 if (This->isRecordingState) {
2755 TRACE("Recording... not performing anything\n");
2759 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2760 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2762 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2767 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2769 TRACE("(%p)\n", This);
2770 *pViewport = This->stateBlock->viewport;
2775 * Get / Set Render States
2776 * TODO: Verify against dx9 definitions
2778 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2781 DWORD oldValue = This->stateBlock->renderState[State];
2783 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2785 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2786 This->updateStateBlock->renderState[State] = Value;
2788 /* Handle recording of state blocks */
2789 if (This->isRecordingState) {
2790 TRACE("Recording... not performing anything\n");
2794 /* Compared here and not before the assignment to allow proper stateblock recording */
2795 if(Value == oldValue) {
2796 TRACE("Application is setting the old value over, nothing to do\n");
2798 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2804 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2806 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2807 *pValue = This->stateBlock->renderState[State];
2812 * Get / Set Sampler States
2813 * TODO: Verify against dx9 definitions
2816 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2820 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2821 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2823 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2824 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2827 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2828 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2829 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2832 * SetSampler is designed to allow for more than the standard up to 8 textures
2833 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2834 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2836 * http://developer.nvidia.com/object/General_FAQ.html#t6
2838 * There are two new settings for GForce
2840 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2841 * and the texture one:
2842 * GL_MAX_TEXTURE_COORDS_ARB.
2843 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2846 oldValue = This->stateBlock->samplerState[Sampler][Type];
2847 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2848 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2850 /* Handle recording of state blocks */
2851 if (This->isRecordingState) {
2852 TRACE("Recording... not performing anything\n");
2856 if(oldValue == Value) {
2857 TRACE("Application is setting the old value over, nothing to do\n");
2861 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2866 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2869 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2870 This, Sampler, debug_d3dsamplerstate(Type), Type);
2872 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2873 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2876 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2877 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2878 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2880 *Value = This->stateBlock->samplerState[Sampler][Type];
2881 TRACE("(%p) : Returning %#x\n", This, *Value);
2886 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2889 This->updateStateBlock->changed.scissorRect = TRUE;
2890 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2891 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2894 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2896 if(This->isRecordingState) {
2897 TRACE("Recording... not performing anything\n");
2901 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2906 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2909 *pRect = This->updateStateBlock->scissorRect;
2910 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2914 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2916 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2918 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2920 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2921 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2923 This->updateStateBlock->vertexDecl = pDecl;
2924 This->updateStateBlock->changed.vertexDecl = TRUE;
2926 if (This->isRecordingState) {
2927 TRACE("Recording... not performing anything\n");
2929 } else if(pDecl == oldDecl) {
2930 /* Checked after the assignment to allow proper stateblock recording */
2931 TRACE("Application is setting the old declaration over, nothing to do\n");
2935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2939 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2942 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2944 *ppDecl = This->stateBlock->vertexDecl;
2945 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2949 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2951 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2953 This->updateStateBlock->vertexShader = pShader;
2954 This->updateStateBlock->changed.vertexShader = TRUE;
2956 if (This->isRecordingState) {
2957 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2958 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2959 TRACE("Recording... not performing anything\n");
2961 } else if(oldShader == pShader) {
2962 /* Checked here to allow proper stateblock recording */
2963 TRACE("App is setting the old shader over, nothing to do\n");
2967 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2968 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2969 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2971 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2976 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2979 if (NULL == ppShader) {
2980 return WINED3DERR_INVALIDCALL;
2982 *ppShader = This->stateBlock->vertexShader;
2983 if( NULL != *ppShader)
2984 IWineD3DVertexShader_AddRef(*ppShader);
2986 TRACE("(%p) : returning %p\n", This, *ppShader);
2990 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2991 IWineD3DDevice *iface,
2993 CONST BOOL *srcData,
2996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2997 unsigned int i, cnt = min(count, MAX_CONST_B - start);
2999 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3000 iface, srcData, start, count);
3002 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3004 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3005 for (i = 0; i < cnt; i++)
3006 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3008 for (i = start; i < cnt + start; ++i) {
3009 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3012 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3017 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3018 IWineD3DDevice *iface,
3023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3024 int cnt = min(count, MAX_CONST_B - start);
3026 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3027 iface, dstData, start, count);
3029 if (dstData == NULL || cnt < 0)
3030 return WINED3DERR_INVALIDCALL;
3032 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3036 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3037 IWineD3DDevice *iface,
3042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3043 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3045 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3046 iface, srcData, start, count);
3048 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3050 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3051 for (i = 0; i < cnt; i++)
3052 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3053 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3055 for (i = start; i < cnt + start; ++i) {
3056 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3059 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3064 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3065 IWineD3DDevice *iface,
3070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3071 int cnt = min(count, MAX_CONST_I - start);
3073 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3074 iface, dstData, start, count);
3076 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= 0)
3077 return WINED3DERR_INVALIDCALL;
3079 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3083 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3084 IWineD3DDevice *iface,
3086 CONST float *srcData,
3089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3092 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3093 iface, srcData, start, count);
3095 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3096 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3097 return WINED3DERR_INVALIDCALL;
3099 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3101 for (i = 0; i < count; i++)
3102 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3103 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3106 if (!This->isRecordingState)
3108 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3109 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3112 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3113 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3118 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3119 IWineD3DDevice *iface,
3124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3125 int cnt = min(count, This->d3d_vshader_constantF - start);
3127 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3128 iface, dstData, start, count);
3130 if (dstData == NULL || cnt < 0)
3131 return WINED3DERR_INVALIDCALL;
3133 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3137 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3139 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3141 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3145 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3147 DWORD i = This->rev_tex_unit_map[unit];
3148 DWORD j = This->texUnitMap[stage];
3150 This->texUnitMap[stage] = unit;
3151 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3153 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3156 This->rev_tex_unit_map[unit] = stage;
3157 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3159 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3163 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3166 This->fixed_function_usage_map = 0;
3167 for (i = 0; i < MAX_TEXTURES; ++i) {
3168 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3169 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3170 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3171 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3172 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3173 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3174 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3175 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3177 if (color_op == WINED3DTOP_DISABLE) {
3178 /* Not used, and disable higher stages */
3182 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3183 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3184 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3185 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3186 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3187 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3188 This->fixed_function_usage_map |= (1 << i);
3191 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3192 This->fixed_function_usage_map |= (1 << (i + 1));
3197 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3199 unsigned int i, tex;
3202 device_update_fixed_function_usage_map(This);
3203 ffu_map = This->fixed_function_usage_map;
3205 if (This->max_ffp_textures == gl_info->limits.texture_stages
3206 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3208 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3210 if (!(ffu_map & 1)) continue;
3212 if (This->texUnitMap[i] != i) {
3213 device_map_stage(This, i, i);
3214 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3215 markTextureStagesDirty(This, i);
3221 /* Now work out the mapping */
3223 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3225 if (!(ffu_map & 1)) continue;
3227 if (This->texUnitMap[i] != tex) {
3228 device_map_stage(This, i, tex);
3229 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3230 markTextureStagesDirty(This, i);
3237 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3239 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3240 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3243 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3244 if (sampler_type[i] && This->texUnitMap[i] != i)
3246 device_map_stage(This, i, i);
3247 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3248 if (i < gl_info->limits.texture_stages)
3250 markTextureStagesDirty(This, i);
3256 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3257 const DWORD *vshader_sampler_tokens, DWORD unit)
3259 DWORD current_mapping = This->rev_tex_unit_map[unit];
3261 /* Not currently used */
3262 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3264 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3265 /* Used by a fragment sampler */
3267 if (!pshader_sampler_tokens) {
3268 /* No pixel shader, check fixed function */
3269 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3272 /* Pixel shader, check the shader's sampler map */
3273 return !pshader_sampler_tokens[current_mapping];
3276 /* Used by a vertex sampler */
3277 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3280 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3282 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3283 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3284 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3285 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3289 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3291 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3292 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3293 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3296 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3297 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3298 if (vshader_sampler_type[i])
3300 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3302 /* Already mapped somewhere */
3306 while (start >= 0) {
3307 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3309 device_map_stage(This, vsampler_idx, start);
3310 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3322 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3324 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3325 BOOL vs = use_vs(This->stateBlock);
3326 BOOL ps = use_ps(This->stateBlock);
3329 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3330 * that would be really messy and require shader recompilation
3331 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3332 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3334 if (ps) device_map_psamplers(This, gl_info);
3335 else device_map_fixed_function_samplers(This, gl_info);
3337 if (vs) device_map_vsamplers(This, ps, gl_info);
3340 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3342 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3343 This->updateStateBlock->pixelShader = pShader;
3344 This->updateStateBlock->changed.pixelShader = TRUE;
3346 /* Handle recording of state blocks */
3347 if (This->isRecordingState) {
3348 TRACE("Recording... not performing anything\n");
3351 if (This->isRecordingState) {
3352 TRACE("Recording... not performing anything\n");
3353 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3354 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3358 if(pShader == oldShader) {
3359 TRACE("App is setting the old pixel shader over, nothing to do\n");
3363 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3364 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3366 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3367 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3372 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3375 if (NULL == ppShader) {
3376 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3377 return WINED3DERR_INVALIDCALL;
3380 *ppShader = This->stateBlock->pixelShader;
3381 if (NULL != *ppShader) {
3382 IWineD3DPixelShader_AddRef(*ppShader);
3384 TRACE("(%p) : returning %p\n", This, *ppShader);
3388 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3389 IWineD3DDevice *iface,
3391 CONST BOOL *srcData,
3394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3395 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3397 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3398 iface, srcData, start, count);
3400 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3402 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3403 for (i = 0; i < cnt; i++)
3404 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3406 for (i = start; i < cnt + start; ++i) {
3407 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3410 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3415 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3416 IWineD3DDevice *iface,
3421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3422 int cnt = min(count, MAX_CONST_B - start);
3424 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3425 iface, dstData, start, count);
3427 if (dstData == NULL || cnt < 0)
3428 return WINED3DERR_INVALIDCALL;
3430 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3434 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3435 IWineD3DDevice *iface,
3440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3441 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3443 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3444 iface, srcData, start, count);
3446 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3448 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3449 for (i = 0; i < cnt; i++)
3450 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3451 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3453 for (i = start; i < cnt + start; ++i) {
3454 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3457 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3462 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3463 IWineD3DDevice *iface,
3468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3469 int cnt = min(count, MAX_CONST_I - start);
3471 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3472 iface, dstData, start, count);
3474 if (dstData == NULL || cnt < 0)
3475 return WINED3DERR_INVALIDCALL;
3477 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3481 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3482 IWineD3DDevice *iface,
3484 CONST float *srcData,
3487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3490 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3491 iface, srcData, start, count);
3493 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3494 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3495 return WINED3DERR_INVALIDCALL;
3497 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3499 for (i = 0; i < count; i++)
3500 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3501 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3504 if (!This->isRecordingState)
3506 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3507 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3510 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3511 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3516 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3517 IWineD3DDevice *iface,
3522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3523 int cnt = min(count, This->d3d_pshader_constantF - start);
3525 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3526 iface, dstData, start, count);
3528 if (dstData == NULL || cnt < 0)
3529 return WINED3DERR_INVALIDCALL;
3531 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3535 /* Context activation is done by the caller. */
3536 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3537 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3538 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3541 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3542 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3545 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3549 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3551 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3554 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3556 ERR("Source has no position mask\n");
3557 return WINED3DERR_INVALIDCALL;
3560 /* We might access VBOs from this code, so hold the lock */
3563 if (dest->resource.allocatedMemory == NULL) {
3564 buffer_get_sysmem(dest);
3567 /* Get a pointer into the destination vbo(create one if none exists) and
3568 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3570 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3572 dest->flags |= WINED3D_BUFFER_CREATEBO;
3573 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3576 if (dest->buffer_object)
3578 unsigned char extrabytes = 0;
3579 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3580 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3581 * this may write 4 extra bytes beyond the area that should be written
3583 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3584 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3585 if(!dest_conv_addr) {
3586 ERR("Out of memory\n");
3587 /* Continue without storing converted vertices */
3589 dest_conv = dest_conv_addr;
3593 * a) WINED3DRS_CLIPPING is enabled
3594 * b) WINED3DVOP_CLIP is passed
3596 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3597 static BOOL warned = FALSE;
3599 * The clipping code is not quite correct. Some things need
3600 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3601 * so disable clipping for now.
3602 * (The graphics in Half-Life are broken, and my processvertices
3603 * test crashes with IDirect3DDevice3)
3609 FIXME("Clipping is broken and disabled for now\n");
3611 } else doClip = FALSE;
3612 dest_ptr = ((char *) buffer_get_sysmem(dest)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3614 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3617 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3618 WINED3DTS_PROJECTION,
3620 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3621 WINED3DTS_WORLDMATRIX(0),
3624 TRACE("View mat:\n");
3625 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);
3626 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);
3627 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);
3628 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);
3630 TRACE("Proj mat:\n");
3631 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);
3632 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);
3633 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);
3634 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);
3636 TRACE("World mat:\n");
3637 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);
3638 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);
3639 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);
3640 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);
3642 /* Get the viewport */
3643 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3644 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3645 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3647 multiply_matrix(&mat,&view_mat,&world_mat);
3648 multiply_matrix(&mat,&proj_mat,&mat);
3650 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3652 for (i = 0; i < dwCount; i+= 1) {
3653 unsigned int tex_index;
3655 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3656 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3657 /* The position first */
3658 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3659 const float *p = (const float *)(element->data + i * element->stride);
3661 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3663 /* Multiplication with world, view and projection matrix */
3664 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);
3665 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);
3666 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);
3667 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);
3669 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3671 /* WARNING: The following things are taken from d3d7 and were not yet checked
3672 * against d3d8 or d3d9!
3675 /* Clipping conditions: From msdn
3677 * A vertex is clipped if it does not match the following requirements
3681 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3683 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3684 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3689 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3690 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3693 /* "Normal" viewport transformation (not clipped)
3694 * 1) The values are divided by rhw
3695 * 2) The y axis is negative, so multiply it with -1
3696 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3697 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3698 * 4) Multiply x with Width/2 and add Width/2
3699 * 5) The same for the height
3700 * 6) Add the viewpoint X and Y to the 2D coordinates and
3701 * The minimum Z value to z
3702 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3704 * Well, basically it's simply a linear transformation into viewport
3716 z *= vp.MaxZ - vp.MinZ;
3718 x += vp.Width / 2 + vp.X;
3719 y += vp.Height / 2 + vp.Y;
3724 /* That vertex got clipped
3725 * Contrary to OpenGL it is not dropped completely, it just
3726 * undergoes a different calculation.
3728 TRACE("Vertex got clipped\n");
3735 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3736 * outside of the main vertex buffer memory. That needs some more
3741 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3744 ( (float *) dest_ptr)[0] = x;
3745 ( (float *) dest_ptr)[1] = y;
3746 ( (float *) dest_ptr)[2] = z;
3747 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3749 dest_ptr += 3 * sizeof(float);
3751 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3752 dest_ptr += sizeof(float);
3757 ( (float *) dest_conv)[0] = x * w;
3758 ( (float *) dest_conv)[1] = y * w;
3759 ( (float *) dest_conv)[2] = z * w;
3760 ( (float *) dest_conv)[3] = w;
3762 dest_conv += 3 * sizeof(float);
3764 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3765 dest_conv += sizeof(float);
3769 if (DestFVF & WINED3DFVF_PSIZE) {
3770 dest_ptr += sizeof(DWORD);
3771 if(dest_conv) dest_conv += sizeof(DWORD);
3773 if (DestFVF & WINED3DFVF_NORMAL) {
3774 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3775 const float *normal = (const float *)(element->data + i * element->stride);
3776 /* AFAIK this should go into the lighting information */
3777 FIXME("Didn't expect the destination to have a normal\n");
3778 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3780 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3784 if (DestFVF & WINED3DFVF_DIFFUSE) {
3785 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3786 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3787 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3789 static BOOL warned = FALSE;
3792 ERR("No diffuse color in source, but destination has one\n");
3796 *( (DWORD *) dest_ptr) = 0xffffffff;
3797 dest_ptr += sizeof(DWORD);
3800 *( (DWORD *) dest_conv) = 0xffffffff;
3801 dest_conv += sizeof(DWORD);
3805 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3807 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3808 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3809 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3810 dest_conv += sizeof(DWORD);
3815 if (DestFVF & WINED3DFVF_SPECULAR)
3817 /* What's the color value in the feedback buffer? */
3818 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3819 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3820 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3822 static BOOL warned = FALSE;
3825 ERR("No specular color in source, but destination has one\n");
3829 *( (DWORD *) dest_ptr) = 0xFF000000;
3830 dest_ptr += sizeof(DWORD);
3833 *( (DWORD *) dest_conv) = 0xFF000000;
3834 dest_conv += sizeof(DWORD);
3838 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3840 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3841 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3842 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3843 dest_conv += sizeof(DWORD);
3848 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3849 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3850 const float *tex_coord = (const float *)(element->data + i * element->stride);
3851 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3853 ERR("No source texture, but destination requests one\n");
3854 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3855 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3858 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3860 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3867 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3868 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3869 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3870 dwCount * get_flexible_vertex_size(DestFVF),
3872 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3873 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3880 #undef copy_and_next
3882 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3883 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3887 struct wined3d_stream_info stream_info;
3888 struct wined3d_context *context;
3889 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3892 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3895 ERR("Output vertex declaration not implemented yet\n");
3898 /* Need any context to write to the vbo. */
3899 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
3901 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3902 * control the streamIsUP flag, thus restore it afterwards.
3904 This->stateBlock->streamIsUP = FALSE;
3905 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3906 This->stateBlock->streamIsUP = streamWasUP;
3908 if(vbo || SrcStartIndex) {
3910 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3911 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3913 * Also get the start index in, but only loop over all elements if there's something to add at all.
3915 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3917 struct wined3d_stream_info_element *e;
3919 if (!(stream_info.use_map & (1 << i))) continue;
3921 e = &stream_info.elements[i];
3922 if (e->buffer_object)
3924 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3925 e->buffer_object = 0;
3926 e->data = (BYTE *)((unsigned long)e->data + (unsigned long)buffer_get_sysmem(vb));
3928 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3929 vb->buffer_object = 0;
3932 if (e->data) e->data += e->stride * SrcStartIndex;
3936 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3937 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3939 context_release(context);
3945 * Get / Set Texture Stage States
3946 * TODO: Verify against dx9 definitions
3948 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3950 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3951 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3953 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3955 if (Stage >= gl_info->limits.texture_stages)
3957 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3958 Stage, gl_info->limits.texture_stages - 1);
3962 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3963 This->updateStateBlock->textureState[Stage][Type] = Value;
3965 if (This->isRecordingState) {
3966 TRACE("Recording... not performing anything\n");
3970 /* Checked after the assignments to allow proper stateblock recording */
3971 if(oldValue == Value) {
3972 TRACE("App is setting the old value over, nothing to do\n");
3976 if(Stage > This->stateBlock->lowest_disabled_stage &&
3977 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3978 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3979 * Changes in other states are important on disabled stages too
3984 if(Type == WINED3DTSS_COLOROP) {
3987 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3988 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3989 * they have to be disabled
3991 * The current stage is dirtified below.
3993 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3994 TRACE("Additionally dirtifying stage %u\n", i);
3995 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3997 This->stateBlock->lowest_disabled_stage = Stage;
3998 TRACE("New lowest disabled: %u\n", Stage);
3999 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4000 /* Previously disabled stage enabled. Stages above it may need enabling
4001 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4002 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4004 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4007 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4009 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4012 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4013 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4015 This->stateBlock->lowest_disabled_stage = i;
4016 TRACE("New lowest disabled: %u\n", i);
4020 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4025 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4027 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4028 *pValue = This->updateStateBlock->textureState[Stage][Type];
4035 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4036 DWORD stage, IWineD3DBaseTexture *texture)
4038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4039 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4040 IWineD3DBaseTexture *prev;
4042 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4044 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4045 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4047 /* Windows accepts overflowing this array... we do not. */
4048 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4050 WARN("Ignoring invalid stage %u.\n", stage);
4054 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4055 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4057 WARN("Rejecting attempt to set scratch texture.\n");
4058 return WINED3DERR_INVALIDCALL;
4061 This->updateStateBlock->changed.textures |= 1 << stage;
4063 prev = This->updateStateBlock->textures[stage];
4064 TRACE("Previous texture %p.\n", prev);
4066 if (texture == prev)
4068 TRACE("App is setting the same texture again, nothing to do.\n");
4072 TRACE("Setting new texture to %p.\n", texture);
4073 This->updateStateBlock->textures[stage] = texture;
4075 if (This->isRecordingState)
4077 TRACE("Recording... not performing anything\n");
4079 if (texture) IWineD3DBaseTexture_AddRef(texture);
4080 if (prev) IWineD3DBaseTexture_Release(prev);
4087 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4088 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4089 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4091 IWineD3DBaseTexture_AddRef(texture);
4093 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4095 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4098 if (!prev && stage < gl_info->limits.texture_stages)
4100 /* The source arguments for color and alpha ops have different
4101 * meanings when a NULL texture is bound, so the COLOROP and
4102 * ALPHAOP have to be dirtified. */
4103 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4107 if (bind_count == 1) t->baseTexture.sampler = stage;
4112 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4113 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4115 IWineD3DBaseTexture_Release(prev);
4117 if (!texture && stage < gl_info->limits.texture_stages)
4119 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4120 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4123 if (bind_count && t->baseTexture.sampler == stage)
4127 /* Search for other stages the texture is bound to. Shouldn't
4128 * happen if applications bind textures to a single stage only. */
4129 TRACE("Searching for other stages the texture is bound to.\n");
4130 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4132 if (This->updateStateBlock->textures[i] == prev)
4134 TRACE("Texture is also bound to stage %u.\n", i);
4135 t->baseTexture.sampler = i;
4142 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4147 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4150 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4152 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4153 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4156 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4157 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4158 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4161 *ppTexture=This->stateBlock->textures[Stage];
4163 IWineD3DBaseTexture_AddRef(*ppTexture);
4165 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4173 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4174 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4176 IWineD3DSwapChain *swapchain;
4179 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4180 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4182 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4185 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4189 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4190 IWineD3DSwapChain_Release(swapchain);
4193 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4200 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4202 WARN("(%p) : stub, calling idirect3d for now\n", This);
4203 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4206 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4208 IWineD3DSwapChain *swapChain;
4211 if(iSwapChain > 0) {
4212 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4213 if (hr == WINED3D_OK) {
4214 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4215 IWineD3DSwapChain_Release(swapChain);
4217 FIXME("(%p) Error getting display mode\n", This);
4220 /* Don't read the real display mode,
4221 but return the stored mode instead. X11 can't change the color
4222 depth, and some apps are pretty angry if they SetDisplayMode from
4223 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4225 Also don't relay to the swapchain because with ddraw it's possible
4226 that there isn't a swapchain at all */
4227 pMode->Width = This->ddraw_width;
4228 pMode->Height = This->ddraw_height;
4229 pMode->Format = This->ddraw_format;
4230 pMode->RefreshRate = 0;
4238 * Stateblock related functions
4241 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4243 IWineD3DStateBlock *stateblock;
4246 TRACE("(%p)\n", This);
4248 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4250 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4251 if (FAILED(hr)) return hr;
4253 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4254 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4255 This->isRecordingState = TRUE;
4257 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4262 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4264 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4266 if (!This->isRecordingState) {
4267 WARN("(%p) not recording! returning error\n", This);
4268 *ppStateBlock = NULL;
4269 return WINED3DERR_INVALIDCALL;
4272 stateblock_init_contained_states(object);
4274 *ppStateBlock = (IWineD3DStateBlock*) object;
4275 This->isRecordingState = FALSE;
4276 This->updateStateBlock = This->stateBlock;
4277 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4278 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4279 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4284 * Scene related functions
4286 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4287 /* At the moment we have no need for any functionality at the beginning
4289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4290 TRACE("(%p)\n", This);
4293 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4294 return WINED3DERR_INVALIDCALL;
4296 This->inScene = TRUE;
4300 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4303 struct wined3d_context *context;
4305 TRACE("(%p)\n", This);
4307 if(!This->inScene) {
4308 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4309 return WINED3DERR_INVALIDCALL;
4312 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
4313 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4315 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4317 context_release(context);
4319 This->inScene = FALSE;
4323 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4324 const RECT *pSourceRect, const RECT *pDestRect,
4325 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4327 IWineD3DSwapChain *swapChain = NULL;
4329 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4331 TRACE("iface %p.\n", iface);
4333 for(i = 0 ; i < swapchains ; i ++) {
4335 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4336 TRACE("presentinng chain %d, %p\n", i, swapChain);
4337 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4338 IWineD3DSwapChain_Release(swapChain);
4344 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const WINED3DVIEWPORT *viewport,
4345 const RECT *scissor_rect, const WINED3DRECT *clear_rect)
4347 /* partial viewport*/
4348 if (viewport->X != 0 || viewport->Y != 0
4349 || viewport->Width < target->currentDesc.Width
4350 || viewport->Height < target->currentDesc.Height)
4353 /* partial scissor rect */
4354 if (scissor_rect && (scissor_rect->left > 0 || scissor_rect->top > 0
4355 || scissor_rect->right < target->currentDesc.Width
4356 || scissor_rect->bottom < target->currentDesc.Height))
4359 /* partial clear rect */
4360 if (clear_rect && (clear_rect->x1 > 0 || clear_rect->y1 > 0
4361 || clear_rect->x2 < target->currentDesc.Width
4362 || clear_rect->y2 < target->currentDesc.Height))
4368 /* Not called from the VTable (internal subroutine) */
4369 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4370 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4372 IWineD3DStateBlockImpl *stateblock = This->stateBlock;
4373 const RECT *scissor_rect = stateblock->renderState[WINED3DRS_SCISSORTESTENABLE] ? &stateblock->scissorRect : NULL;
4374 const WINED3DRECT *clear_rect = (Count > 0 && pRects) ? pRects : NULL;
4375 IWineD3DSurfaceImpl *depth_stencil = This->depth_stencil;
4376 const WINED3DVIEWPORT *vp = &stateblock->viewport;
4377 GLbitfield glMask = 0;
4379 WINED3DRECT curRect;
4381 UINT drawable_width, drawable_height;
4382 struct wined3d_context *context;
4384 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4385 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4386 * for the cleared parts, and the untouched parts.
4388 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4389 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4390 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4391 * checking all this if the dest surface is in the drawable anyway.
4393 if (Flags & WINED3DCLEAR_TARGET && !(target->Flags & SFLAG_INDRAWABLE))
4395 if (!is_full_clear(target, vp, scissor_rect, clear_rect))
4396 IWineD3DSurface_LoadLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, NULL);
4399 context = context_acquire(This, target, CTXUSAGE_CLEAR);
4400 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
4402 if (!surface_is_offscreen(target))
4404 TRACE("Surface %p is onscreen\n", target);
4407 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4408 context_set_draw_buffer(context, surface_get_gl_buffer(target));
4413 TRACE("Surface %p is offscreen\n", target);
4416 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
4417 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, target);
4418 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, depth_stencil, TRUE);
4423 if (!context->valid)
4425 context_release(context);
4426 WARN("Invalid context, skipping clear.\n");
4430 target->get_drawable_size(context, &drawable_width, &drawable_height);
4434 /* Only set the values up once, as they are not changing */
4435 if (Flags & WINED3DCLEAR_STENCIL)
4437 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
4439 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
4440 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
4443 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
4444 glClearStencil(Stencil);
4445 checkGLcall("glClearStencil");
4446 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4449 if (Flags & WINED3DCLEAR_ZBUFFER)
4451 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4453 if (location == SFLAG_DS_ONSCREEN && depth_stencil != This->onscreen_depth_stencil)
4454 device_switch_onscreen_ds(This, context, depth_stencil);
4456 if (!(depth_stencil->Flags & location) && !is_full_clear(depth_stencil, vp, scissor_rect, clear_rect))
4457 surface_load_ds_location(depth_stencil, context, location);
4458 surface_modify_ds_location(depth_stencil, location);
4460 glDepthMask(GL_TRUE);
4461 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4463 checkGLcall("glClearDepth");
4464 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4467 if (Flags & WINED3DCLEAR_TARGET)
4469 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4471 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4472 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
4473 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
4474 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
4475 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
4476 glClearColor(D3DCOLOR_R(Color), D3DCOLOR_G(Color), D3DCOLOR_B(Color), D3DCOLOR_A(Color));
4477 checkGLcall("glClearColor");
4478 glMask = glMask | GL_COLOR_BUFFER_BIT;
4481 vp_rect.left = vp->X;
4482 vp_rect.top = vp->Y;
4483 vp_rect.right = vp->X + vp->Width;
4484 vp_rect.bottom = vp->Y + vp->Height;
4485 if (!(Count > 0 && pRects)) {
4486 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4487 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4489 if (context->render_offscreen)
4491 glScissor(vp_rect.left, vp_rect.top,
4492 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4494 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4495 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4497 checkGLcall("glScissor");
4499 checkGLcall("glClear");
4501 /* Now process each rect in turn */
4502 for (i = 0; i < Count; i++) {
4503 /* Note gl uses lower left, width/height */
4504 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
4505 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4506 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4508 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4509 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4510 curRect.x1, (target->currentDesc.Height - curRect.y2),
4511 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4513 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4514 * The rectangle is not cleared, no error is returned, but further rectanlges are
4515 * still cleared if they are valid
4517 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4518 TRACE("Rectangle with negative dimensions, ignoring\n");
4522 if (context->render_offscreen)
4524 glScissor(curRect.x1, curRect.y1,
4525 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4527 glScissor(curRect.x1, drawable_height - curRect.y2,
4528 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4530 checkGLcall("glScissor");
4533 checkGLcall("glClear");
4539 if (wined3d_settings.strict_draw_ordering || ((target->Flags & SFLAG_SWAPCHAIN)
4540 && ((IWineD3DSwapChainImpl *)target->container)->front_buffer == target))
4541 wglFlush(); /* Flush to ensure ordering across contexts. */
4543 context_release(context);
4548 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count,
4549 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4553 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4554 Count, pRects, Flags, Color, Z, Stencil);
4556 if (Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !This->depth_stencil)
4558 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4559 /* TODO: What about depth stencil buffers without stencil bits? */
4560 return WINED3DERR_INVALIDCALL;
4563 return IWineD3DDeviceImpl_ClearSurface(This, This->render_targets[0], Count, pRects, Flags, Color, Z, Stencil);
4570 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4571 WINED3DPRIMITIVETYPE primitive_type)
4573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4575 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4577 This->updateStateBlock->changed.primitive_type = TRUE;
4578 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4581 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4582 WINED3DPRIMITIVETYPE *primitive_type)
4584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4586 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4588 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4590 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4593 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4597 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4599 if(!This->stateBlock->vertexDecl) {
4600 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4601 return WINED3DERR_INVALIDCALL;
4604 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4605 if(This->stateBlock->streamIsUP) {
4606 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4607 This->stateBlock->streamIsUP = FALSE;
4610 if(This->stateBlock->loadBaseVertexIndex != 0) {
4611 This->stateBlock->loadBaseVertexIndex = 0;
4612 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4614 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4615 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4619 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4623 IWineD3DBuffer *pIB;
4626 pIB = This->stateBlock->pIndexData;
4628 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4629 * without an index buffer set. (The first time at least...)
4630 * D3D8 simply dies, but I doubt it can do much harm to return
4631 * D3DERR_INVALIDCALL there as well. */
4632 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4633 return WINED3DERR_INVALIDCALL;
4636 if(!This->stateBlock->vertexDecl) {
4637 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4638 return WINED3DERR_INVALIDCALL;
4641 if(This->stateBlock->streamIsUP) {
4642 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4643 This->stateBlock->streamIsUP = FALSE;
4645 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4647 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4649 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4655 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4656 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4657 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4660 drawPrimitive(iface, index_count, startIndex, idxStride,
4661 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4666 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4667 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4672 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4673 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4675 if(!This->stateBlock->vertexDecl) {
4676 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4677 return WINED3DERR_INVALIDCALL;
4680 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4681 vb = This->stateBlock->streamSource[0];
4682 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4683 if (vb) IWineD3DBuffer_Release(vb);
4684 This->stateBlock->streamOffset[0] = 0;
4685 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4686 This->stateBlock->streamIsUP = TRUE;
4687 This->stateBlock->loadBaseVertexIndex = 0;
4689 /* TODO: Only mark dirty if drawing from a different UP address */
4690 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4692 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4694 /* MSDN specifies stream zero settings must be set to NULL */
4695 This->stateBlock->streamStride[0] = 0;
4696 This->stateBlock->streamSource[0] = NULL;
4698 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4699 * the new stream sources or use UP drawing again
4704 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4705 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4706 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4713 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4714 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4716 if(!This->stateBlock->vertexDecl) {
4717 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4718 return WINED3DERR_INVALIDCALL;
4721 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4727 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4728 vb = This->stateBlock->streamSource[0];
4729 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4730 if (vb) IWineD3DBuffer_Release(vb);
4731 This->stateBlock->streamIsUP = TRUE;
4732 This->stateBlock->streamOffset[0] = 0;
4733 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4735 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4736 This->stateBlock->baseVertexIndex = 0;
4737 This->stateBlock->loadBaseVertexIndex = 0;
4738 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4739 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4740 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4742 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4744 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4745 This->stateBlock->streamSource[0] = NULL;
4746 This->stateBlock->streamStride[0] = 0;
4747 ib = This->stateBlock->pIndexData;
4749 IWineD3DBuffer_Release(ib);
4750 This->stateBlock->pIndexData = NULL;
4752 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4753 * SetStreamSource to specify a vertex buffer
4759 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4760 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4764 /* Mark the state dirty until we have nicer tracking
4765 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4768 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4769 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4770 This->stateBlock->baseVertexIndex = 0;
4771 This->up_strided = DrawPrimStrideData;
4772 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4773 This->up_strided = NULL;
4777 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4778 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4779 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4782 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4784 /* Mark the state dirty until we have nicer tracking
4785 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4788 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4789 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4790 This->stateBlock->streamIsUP = TRUE;
4791 This->stateBlock->baseVertexIndex = 0;
4792 This->up_strided = DrawPrimStrideData;
4793 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4794 This->up_strided = NULL;
4798 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4799 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4800 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4802 WINED3DLOCKED_BOX src;
4803 WINED3DLOCKED_BOX dst;
4806 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4807 iface, pSourceVolume, pDestinationVolume);
4809 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4810 * dirtification to improve loading performance.
4812 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4813 if(FAILED(hr)) return hr;
4814 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4816 IWineD3DVolume_UnlockBox(pSourceVolume);
4820 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4822 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4824 IWineD3DVolume_UnlockBox(pSourceVolume);
4826 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4831 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4832 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4834 unsigned int level_count, i;
4835 WINED3DRESOURCETYPE type;
4838 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4840 /* Verify that the source and destination textures are non-NULL. */
4841 if (!src_texture || !dst_texture)
4843 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4844 return WINED3DERR_INVALIDCALL;
4847 if (src_texture == dst_texture)
4849 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4850 return WINED3DERR_INVALIDCALL;
4853 /* Verify that the source and destination textures are the same type. */
4854 type = IWineD3DBaseTexture_GetType(src_texture);
4855 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4857 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4858 return WINED3DERR_INVALIDCALL;
4861 /* Check that both textures have the identical numbers of levels. */
4862 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4863 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4865 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4866 return WINED3DERR_INVALIDCALL;
4869 /* Make sure that the destination texture is loaded. */
4870 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4872 /* Update every surface level of the texture. */
4875 case WINED3DRTYPE_TEXTURE:
4877 IWineD3DSurface *src_surface;
4878 IWineD3DSurface *dst_surface;
4880 for (i = 0; i < level_count; ++i)
4882 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4883 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4884 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4885 IWineD3DSurface_Release(dst_surface);
4886 IWineD3DSurface_Release(src_surface);
4889 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4896 case WINED3DRTYPE_CUBETEXTURE:
4898 IWineD3DSurface *src_surface;
4899 IWineD3DSurface *dst_surface;
4900 WINED3DCUBEMAP_FACES face;
4902 for (i = 0; i < level_count; ++i)
4904 /* Update each cube face. */
4905 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4907 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4908 face, i, &src_surface);
4909 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4910 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4911 face, i, &dst_surface);
4912 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4913 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4914 IWineD3DSurface_Release(dst_surface);
4915 IWineD3DSurface_Release(src_surface);
4918 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4926 case WINED3DRTYPE_VOLUMETEXTURE:
4928 IWineD3DVolume *src_volume;
4929 IWineD3DVolume *dst_volume;
4931 for (i = 0; i < level_count; ++i)
4933 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4934 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4935 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4936 IWineD3DVolume_Release(dst_volume);
4937 IWineD3DVolume_Release(src_volume);
4940 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4948 FIXME("Unsupported texture type %#x.\n", type);
4949 return WINED3DERR_INVALIDCALL;
4955 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4956 IWineD3DSwapChain *swapChain;
4958 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4959 if(hr == WINED3D_OK) {
4960 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4961 IWineD3DSwapChain_Release(swapChain);
4966 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4968 IWineD3DBaseTextureImpl *texture;
4971 TRACE("(%p) : %p\n", This, pNumPasses);
4973 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4974 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
4975 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4976 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4978 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
4979 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4980 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4983 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
4984 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
4986 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
4987 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4990 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
4991 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4994 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
4995 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
4996 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5001 /* return a sensible default */
5004 TRACE("returning D3D_OK\n");
5008 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5012 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5014 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5015 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5016 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5018 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5023 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5027 PALETTEENTRY **palettes;
5029 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5031 if (PaletteNumber >= MAX_PALETTES) {
5032 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5033 return WINED3DERR_INVALIDCALL;
5036 if (PaletteNumber >= This->NumberOfPalettes) {
5037 NewSize = This->NumberOfPalettes;
5040 } while(PaletteNumber >= NewSize);
5041 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5043 ERR("Out of memory!\n");
5044 return E_OUTOFMEMORY;
5046 This->palettes = palettes;
5047 This->NumberOfPalettes = NewSize;
5050 if (!This->palettes[PaletteNumber]) {
5051 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5052 if (!This->palettes[PaletteNumber]) {
5053 ERR("Out of memory!\n");
5054 return E_OUTOFMEMORY;
5058 for (j = 0; j < 256; ++j) {
5059 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5060 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5061 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5062 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5064 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5065 TRACE("(%p) : returning\n", This);
5069 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5072 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5073 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5074 /* What happens in such situation isn't documented; Native seems to silently abort
5075 on such conditions. Return Invalid Call. */
5076 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5077 return WINED3DERR_INVALIDCALL;
5079 for (j = 0; j < 256; ++j) {
5080 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5081 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5082 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5083 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5085 TRACE("(%p) : returning\n", This);
5089 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5091 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5092 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5093 (tested with reference rasterizer). Return Invalid Call. */
5094 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5095 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5096 return WINED3DERR_INVALIDCALL;
5098 /*TODO: stateblocks */
5099 if (This->currentPalette != PaletteNumber) {
5100 This->currentPalette = PaletteNumber;
5101 dirtify_p8_texture_samplers(This);
5103 TRACE("(%p) : returning\n", This);
5107 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5109 if (PaletteNumber == NULL) {
5110 WARN("(%p) : returning Invalid Call\n", This);
5111 return WINED3DERR_INVALIDCALL;
5113 /*TODO: stateblocks */
5114 *PaletteNumber = This->currentPalette;
5115 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5119 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5124 FIXME("(%p) : stub\n", This);
5128 This->softwareVertexProcessing = bSoftware;
5133 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5138 FIXME("(%p) : stub\n", This);
5141 return This->softwareVertexProcessing;
5144 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5145 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5147 IWineD3DSwapChain *swapchain;
5150 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5151 iface, swapchain_idx, raster_status);
5153 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5156 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5160 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5161 IWineD3DSwapChain_Release(swapchain);
5164 WARN("Failed to get raster status, hr %#x.\n", hr);
5171 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5174 if(nSegments != 0.0f) {
5177 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5184 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5189 FIXME("iface %p stub!\n", iface);
5195 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5196 IWineD3DSurface *src_surface, const RECT *src_rect,
5197 IWineD3DSurface *dst_surface, const POINT *dst_point)
5199 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5200 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5202 const struct wined3d_format_desc *src_format;
5203 const struct wined3d_format_desc *dst_format;
5204 struct wined3d_context *context;
5205 const unsigned char *data;
5206 UINT update_w, update_h;
5207 CONVERT_TYPES convert;
5211 struct wined3d_format_desc dummy_desc;
5213 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5214 iface, src_surface, wine_dbgstr_rect(src_rect),
5215 dst_surface, wine_dbgstr_point(dst_point));
5217 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5219 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5220 src_surface, dst_surface);
5221 return WINED3DERR_INVALIDCALL;
5224 src_format = src_impl->resource.format_desc;
5225 dst_format = dst_impl->resource.format_desc;
5227 if (src_format->format != dst_format->format)
5229 WARN("Source and destination surfaces should have the same format.\n");
5230 return WINED3DERR_INVALIDCALL;
5233 dst_x = dst_point ? dst_point->x : 0;
5234 dst_y = dst_point ? dst_point->y : 0;
5236 /* This call loads the OpenGL surface directly, instead of copying the
5237 * surface to the destination's sysmem copy. If surface conversion is
5238 * needed, use BltFast instead to copy in sysmem and use regular surface
5240 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &dummy_desc, &convert);
5241 if (convert != NO_CONVERSION)
5242 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5244 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5247 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5248 checkGLcall("glActiveTextureARB");
5251 /* Make sure the surface is loaded and up to date */
5252 surface_internal_preload(dst_impl, SRGB_RGB);
5253 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5255 src_w = src_impl->currentDesc.Width;
5256 src_h = src_impl->currentDesc.Height;
5257 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5258 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5260 data = IWineD3DSurface_GetData(src_surface);
5261 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5265 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5267 UINT row_length = (update_w / src_format->block_width) * src_format->block_byte_count;
5268 UINT row_count = update_h / src_format->block_height;
5269 UINT src_pitch = IWineD3DSurface_GetPitch(src_surface);
5273 data += (src_rect->top / src_format->block_height) * src_pitch;
5274 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5277 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5278 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5279 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5281 if (row_length == src_pitch)
5283 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5284 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5290 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5291 * can't use the unpack row length like below. */
5292 for (row = 0, y = dst_y; row < row_count; ++row)
5294 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5295 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5296 y += src_format->block_height;
5300 checkGLcall("glCompressedTexSubImage2DARB");
5306 data += src_rect->top * src_w * src_format->byte_count;
5307 data += src_rect->left * src_format->byte_count;
5310 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5311 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5312 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5314 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5315 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5316 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5317 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5318 checkGLcall("glTexSubImage2D");
5322 context_release(context);
5324 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INTEXTURE, TRUE);
5325 sampler = This->rev_tex_unit_map[0];
5326 if (sampler != WINED3D_UNMAPPED_STAGE)
5328 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5334 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5336 struct WineD3DRectPatch *patch;
5337 GLenum old_primitive_type;
5341 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5343 if(!(Handle || pRectPatchInfo)) {
5344 /* TODO: Write a test for the return value, thus the FIXME */
5345 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5346 return WINED3DERR_INVALIDCALL;
5350 i = PATCHMAP_HASHFUNC(Handle);
5352 LIST_FOR_EACH(e, &This->patches[i]) {
5353 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5354 if(patch->Handle == Handle) {
5361 TRACE("Patch does not exist. Creating a new one\n");
5362 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5363 patch->Handle = Handle;
5364 list_add_head(&This->patches[i], &patch->entry);
5366 TRACE("Found existing patch %p\n", patch);
5369 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5370 * attributes we have to tesselate, read back, and draw. This needs a patch
5371 * management structure instance. Create one.
5373 * A possible improvement is to check if a vertex shader is used, and if not directly
5376 FIXME("Drawing an uncached patch. This is slow\n");
5377 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5380 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5381 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5382 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5384 TRACE("Tesselation density or patch info changed, retesselating\n");
5386 if(pRectPatchInfo) {
5387 patch->RectPatchInfo = *pRectPatchInfo;
5389 patch->numSegs[0] = pNumSegs[0];
5390 patch->numSegs[1] = pNumSegs[1];
5391 patch->numSegs[2] = pNumSegs[2];
5392 patch->numSegs[3] = pNumSegs[3];
5394 hr = tesselate_rectpatch(This, patch);
5396 WARN("Patch tesselation failed\n");
5398 /* Do not release the handle to store the params of the patch */
5400 HeapFree(GetProcessHeap(), 0, patch);
5406 This->currentPatch = patch;
5407 old_primitive_type = This->stateBlock->gl_primitive_type;
5408 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5409 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5410 This->stateBlock->gl_primitive_type = old_primitive_type;
5411 This->currentPatch = NULL;
5413 /* Destroy uncached patches */
5415 HeapFree(GetProcessHeap(), 0, patch->mem);
5416 HeapFree(GetProcessHeap(), 0, patch);
5421 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5422 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5424 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5425 iface, handle, segment_count, patch_info);
5430 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5433 struct WineD3DRectPatch *patch;
5435 TRACE("(%p) Handle(%d)\n", This, Handle);
5437 i = PATCHMAP_HASHFUNC(Handle);
5438 LIST_FOR_EACH(e, &This->patches[i]) {
5439 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5440 if(patch->Handle == Handle) {
5441 TRACE("Deleting patch %p\n", patch);
5442 list_remove(&patch->entry);
5443 HeapFree(GetProcessHeap(), 0, patch->mem);
5444 HeapFree(GetProcessHeap(), 0, patch);
5449 /* TODO: Write a test for the return value */
5450 FIXME("Attempt to destroy nonexistent patch\n");
5451 return WINED3DERR_INVALIDCALL;
5454 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurfaceImpl *surface,
5455 const WINED3DRECT *rect, const float color[4])
5457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5458 struct wined3d_context *context;
5460 if (rect) IWineD3DSurface_LoadLocation((IWineD3DSurface *)surface, SFLAG_INDRAWABLE, NULL);
5461 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)surface, SFLAG_INDRAWABLE, TRUE);
5463 if (!surface_is_offscreen(surface))
5465 TRACE("Surface %p is onscreen\n", surface);
5467 context = context_acquire(This, surface, CTXUSAGE_RESOURCELOAD);
5469 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
5470 context_set_draw_buffer(context, surface_get_gl_buffer(surface));
5474 TRACE("Surface %p is offscreen\n", surface);
5476 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5478 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
5479 context_attach_surface_fbo(context, GL_FRAMEBUFFER, 0, surface);
5480 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, NULL, FALSE);
5484 glEnable(GL_SCISSOR_TEST);
5485 if (surface_is_offscreen(surface))
5486 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5488 glScissor(rect->x1, surface->currentDesc.Height - rect->y2,
5489 rect->x2 - rect->x1, rect->y2 - rect->y1);
5490 checkGLcall("glScissor");
5491 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5493 glDisable(GL_SCISSOR_TEST);
5495 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5497 glDisable(GL_BLEND);
5498 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
5500 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5502 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
5503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
5504 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
5506 glClearColor(color[0], color[1], color[2], color[3]);
5507 glClear(GL_COLOR_BUFFER_BIT);
5508 checkGLcall("glClear");
5512 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5514 context_release(context);
5517 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5518 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5520 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5523 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5525 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5526 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5527 return WINED3DERR_INVALIDCALL;
5530 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5531 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5532 color_fill_fbo(iface, surface, pRect, c);
5535 /* Just forward this to the DirectDraw blitting engine */
5536 memset(&BltFx, 0, sizeof(BltFx));
5537 BltFx.dwSize = sizeof(BltFx);
5538 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(color, surface->resource.format_desc->format);
5539 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5540 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5544 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5545 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5547 IWineD3DResource *resource;
5548 IWineD3DSurfaceImpl *surface;
5551 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5554 ERR("Failed to get resource, hr %#x\n", hr);
5558 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5560 FIXME("Only supported on surface resources\n");
5561 IWineD3DResource_Release(resource);
5565 surface = (IWineD3DSurfaceImpl *)resource;
5567 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5569 color_fill_fbo(iface, surface, NULL, color);
5576 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5578 c = ((DWORD)(color[2] * 255.0f));
5579 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5580 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5581 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5583 /* Just forward this to the DirectDraw blitting engine */
5584 memset(&BltFx, 0, sizeof(BltFx));
5585 BltFx.dwSize = sizeof(BltFx);
5586 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(c, surface->resource.format_desc->format);
5587 hr = IWineD3DSurface_Blt((IWineD3DSurface *)surface, NULL, NULL, NULL,
5588 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5591 ERR("Blt failed, hr %#x\n", hr);
5595 IWineD3DResource_Release(resource);
5598 /* rendertarget and depth stencil functions */
5599 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5602 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5604 ERR("(%p) : Only %d render targets are supported.\n",
5605 This, This->adapter->gl_info.limits.buffers);
5606 return WINED3DERR_INVALIDCALL;
5609 *ppRenderTarget = (IWineD3DSurface *)This->render_targets[RenderTargetIndex];
5610 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5611 /* Note inc ref on returned surface */
5612 if(*ppRenderTarget != NULL)
5613 IWineD3DSurface_AddRef(*ppRenderTarget);
5617 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5618 IWineD3DSurface *front, IWineD3DSurface *back)
5620 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5621 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5622 IWineD3DSwapChainImpl *swapchain;
5625 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5627 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5629 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5633 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5635 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5636 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5637 return WINED3DERR_INVALIDCALL;
5642 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5644 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5645 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5646 return WINED3DERR_INVALIDCALL;
5649 if (!swapchain->back_buffers)
5651 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5652 if (!swapchain->back_buffers)
5654 ERR("Failed to allocate back buffer array memory.\n");
5655 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5656 return E_OUTOFMEMORY;
5661 if (swapchain->front_buffer != front_impl)
5663 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5665 if (swapchain->front_buffer)
5667 IWineD3DSurface_SetContainer((IWineD3DSurface *)swapchain->front_buffer, NULL);
5668 swapchain->front_buffer->Flags &= ~SFLAG_SWAPCHAIN;
5670 swapchain->front_buffer = front_impl;
5674 IWineD3DSurface_SetContainer(front, (IWineD3DBase *)swapchain);
5675 front_impl->Flags |= SFLAG_SWAPCHAIN;
5679 if (swapchain->back_buffers[0] != back_impl)
5681 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5683 if (swapchain->back_buffers[0])
5685 IWineD3DSurface_SetContainer((IWineD3DSurface *)swapchain->back_buffers[0], NULL);
5686 swapchain->back_buffers[0]->Flags &= ~SFLAG_SWAPCHAIN;
5688 swapchain->back_buffers[0] = back_impl;
5692 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5693 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5694 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->format;
5695 swapchain->presentParms.BackBufferCount = 1;
5697 IWineD3DSurface_SetContainer(back, (IWineD3DBase *)swapchain);
5698 back_impl->Flags |= SFLAG_SWAPCHAIN;
5702 swapchain->presentParms.BackBufferCount = 0;
5703 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5704 swapchain->back_buffers = NULL;
5708 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5712 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5714 *ppZStencilSurface = (IWineD3DSurface *)This->depth_stencil;
5715 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5717 if(*ppZStencilSurface != NULL) {
5718 /* Note inc ref on returned surface */
5719 IWineD3DSurface_AddRef(*ppZStencilSurface);
5722 return WINED3DERR_NOTFOUND;
5726 void stretch_rect_fbo(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *src_surface, const RECT *src_rect_in,
5727 IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect_in, const WINED3DTEXTUREFILTERTYPE filter)
5729 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5730 const struct wined3d_gl_info *gl_info;
5731 struct wined3d_context *context;
5733 POINT offset = {0, 0};
5734 RECT src_rect, dst_rect;
5736 TRACE("device %p, src_surface %p, src_rect_in %s, dst_surface %p, dst_rect_in %s, filter %s (0x%08x).\n",
5737 device, src_surface, wine_dbgstr_rect(src_rect_in), dst_surface,
5738 wine_dbgstr_rect(dst_rect_in), debug_d3dtexturefiltertype(filter), filter);
5740 src_rect = *src_rect_in;
5741 dst_rect = *dst_rect_in;
5744 case WINED3DTEXF_LINEAR:
5745 gl_filter = GL_LINEAR;
5749 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5750 case WINED3DTEXF_NONE:
5751 case WINED3DTEXF_POINT:
5752 gl_filter = GL_NEAREST;
5756 /* Make sure the drawables are up-to-date. Note that loading the
5757 * destination surface isn't strictly required if we overwrite the
5758 * entire surface. */
5759 IWineD3DSurface_LoadLocation((IWineD3DSurface *)src_surface, SFLAG_INDRAWABLE, NULL);
5760 IWineD3DSurface_LoadLocation((IWineD3DSurface *)dst_surface, SFLAG_INDRAWABLE, NULL);
5762 if (!surface_is_offscreen(src_surface)) context = context_acquire(device, src_surface, CTXUSAGE_RESOURCELOAD);
5763 else if (!surface_is_offscreen(dst_surface)) context = context_acquire(device, dst_surface, CTXUSAGE_RESOURCELOAD);
5764 else context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
5766 if (!context->valid)
5768 context_release(context);
5769 WARN("Invalid context, skipping blit.\n");
5773 gl_info = context->gl_info;
5775 if (!surface_is_offscreen(src_surface))
5777 GLenum buffer = surface_get_gl_buffer(src_surface);
5779 TRACE("Source surface %p is onscreen\n", src_surface);
5781 if(buffer == GL_FRONT) {
5784 ClientToScreen(context->win_handle, &offset);
5785 GetClientRect(context->win_handle, &windowsize);
5786 h = windowsize.bottom - windowsize.top;
5787 src_rect.left -= offset.x; src_rect.right -=offset.x;
5788 src_rect.top = offset.y + h - src_rect.top;
5789 src_rect.bottom = offset.y + h - src_rect.bottom;
5791 src_rect.top = src_surface->currentDesc.Height - src_rect.top;
5792 src_rect.bottom = src_surface->currentDesc.Height - src_rect.bottom;
5796 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5797 glReadBuffer(buffer);
5798 checkGLcall("glReadBuffer()");
5800 TRACE("Source surface %p is offscreen\n", src_surface);
5802 context_bind_fbo(context, GL_READ_FRAMEBUFFER, &context->src_fbo);
5803 context_attach_surface_fbo(context, GL_READ_FRAMEBUFFER, 0, src_surface);
5804 glReadBuffer(GL_COLOR_ATTACHMENT0);
5805 checkGLcall("glReadBuffer()");
5806 context_attach_depth_stencil_fbo(context, GL_READ_FRAMEBUFFER, NULL, FALSE);
5810 /* Attach dst surface to dst fbo */
5811 if (!surface_is_offscreen(dst_surface))
5813 GLenum buffer = surface_get_gl_buffer(dst_surface);
5815 TRACE("Destination surface %p is onscreen\n", dst_surface);
5817 if(buffer == GL_FRONT) {
5820 ClientToScreen(context->win_handle, &offset);
5821 GetClientRect(context->win_handle, &windowsize);
5822 h = windowsize.bottom - windowsize.top;
5823 dst_rect.left -= offset.x; dst_rect.right -=offset.x;
5824 dst_rect.top = offset.y + h - dst_rect.top;
5825 dst_rect.bottom = offset.y + h - dst_rect.bottom;
5827 /* Screen coords = window coords, surface height = window height */
5828 dst_rect.top = dst_surface->currentDesc.Height - dst_rect.top;
5829 dst_rect.bottom = dst_surface->currentDesc.Height - dst_rect.bottom;
5833 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5834 context_set_draw_buffer(context, buffer);
5838 TRACE("Destination surface %p is offscreen\n", dst_surface);
5841 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, &context->dst_fbo);
5842 context_attach_surface_fbo(context, GL_DRAW_FRAMEBUFFER, 0, dst_surface);
5843 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5844 context_attach_depth_stencil_fbo(context, GL_DRAW_FRAMEBUFFER, NULL, FALSE);
5846 glDisable(GL_SCISSOR_TEST);
5847 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5849 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
5850 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, mask, gl_filter);
5851 checkGLcall("glBlitFramebuffer()");
5855 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5857 context_release(context);
5859 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)dst_surface, SFLAG_INDRAWABLE, TRUE);
5862 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5863 BOOL set_viewport) {
5864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5866 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5868 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5870 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5871 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5872 return WINED3DERR_INVALIDCALL;
5875 /* MSDN says that null disables the render target
5876 but a device must always be associated with a render target
5877 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5879 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5880 FIXME("Trying to set render target 0 to NULL\n");
5881 return WINED3DERR_INVALIDCALL;
5883 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5884 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);
5885 return WINED3DERR_INVALIDCALL;
5888 /* If we are trying to set what we already have, don't bother */
5889 if (pRenderTarget == (IWineD3DSurface *)This->render_targets[RenderTargetIndex])
5891 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5895 IWineD3DSurface_AddRef(pRenderTarget);
5896 if (This->render_targets[RenderTargetIndex])
5897 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[RenderTargetIndex]);
5898 This->render_targets[RenderTargetIndex] = (IWineD3DSurfaceImpl *)pRenderTarget;
5900 /* Render target 0 is special */
5901 if(RenderTargetIndex == 0 && set_viewport) {
5902 /* Finally, reset the viewport and scissor rect as the MSDN states.
5903 * Tests show that stateblock recording is ignored, the change goes
5904 * directly into the primary stateblock.
5906 This->stateBlock->viewport.Height = This->render_targets[0]->currentDesc.Height;
5907 This->stateBlock->viewport.Width = This->render_targets[0]->currentDesc.Width;
5908 This->stateBlock->viewport.X = 0;
5909 This->stateBlock->viewport.Y = 0;
5910 This->stateBlock->viewport.MaxZ = 1.0f;
5911 This->stateBlock->viewport.MinZ = 0.0f;
5912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5914 This->stateBlock->scissorRect.top = 0;
5915 This->stateBlock->scissorRect.left = 0;
5916 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5917 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5918 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5923 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5925 IWineD3DSurfaceImpl *tmp;
5927 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, pNewZStencil, This->depth_stencil);
5929 if (This->depth_stencil == (IWineD3DSurfaceImpl *)pNewZStencil)
5931 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5935 if (This->depth_stencil)
5937 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5938 || This->depth_stencil->Flags & SFLAG_DISCARD)
5940 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED);
5941 if (This->depth_stencil == This->onscreen_depth_stencil)
5943 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5944 This->onscreen_depth_stencil = NULL;
5949 tmp = This->depth_stencil;
5950 This->depth_stencil = (IWineD3DSurfaceImpl *)pNewZStencil;
5951 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5952 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5954 if ((!tmp && pNewZStencil) || (!pNewZStencil && tmp))
5956 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5957 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5958 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5959 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5965 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5966 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5968 /* TODO: the use of Impl is deprecated. */
5969 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5970 WINED3DLOCKED_RECT lockedRect;
5972 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5974 /* some basic validation checks */
5975 if(This->cursorTexture) {
5976 struct wined3d_context *context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
5978 glDeleteTextures(1, &This->cursorTexture);
5980 context_release(context);
5981 This->cursorTexture = 0;
5984 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5985 This->haveHardwareCursor = TRUE;
5987 This->haveHardwareCursor = FALSE;
5990 WINED3DLOCKED_RECT rect;
5992 /* MSDN: Cursor must be A8R8G8B8 */
5993 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
5995 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5996 return WINED3DERR_INVALIDCALL;
5999 /* MSDN: Cursor must be smaller than the display mode */
6000 if(pSur->currentDesc.Width > This->ddraw_width ||
6001 pSur->currentDesc.Height > This->ddraw_height) {
6002 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);
6003 return WINED3DERR_INVALIDCALL;
6006 if (!This->haveHardwareCursor) {
6007 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6009 /* Do not store the surface's pointer because the application may
6010 * release it after setting the cursor image. Windows doesn't
6011 * addref the set surface, so we can't do this either without
6012 * creating circular refcount dependencies. Copy out the gl texture
6015 This->cursorWidth = pSur->currentDesc.Width;
6016 This->cursorHeight = pSur->currentDesc.Height;
6017 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6019 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6020 const struct wined3d_format_desc *format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6021 struct wined3d_context *context;
6022 char *mem, *bits = rect.pBits;
6023 GLint intfmt = format_desc->glInternal;
6024 GLint format = format_desc->glFormat;
6025 GLint type = format_desc->glType;
6026 INT height = This->cursorHeight;
6027 INT width = This->cursorWidth;
6028 INT bpp = format_desc->byte_count;
6032 /* Reformat the texture memory (pitch and width can be
6034 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6035 for(i = 0; i < height; i++)
6036 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6037 IWineD3DSurface_UnlockRect(pCursorBitmap);
6039 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6043 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6045 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6046 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6049 /* Make sure that a proper texture unit is selected */
6050 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6051 checkGLcall("glActiveTextureARB");
6052 sampler = This->rev_tex_unit_map[0];
6053 if (sampler != WINED3D_UNMAPPED_STAGE)
6055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6057 /* Create a new cursor texture */
6058 glGenTextures(1, &This->cursorTexture);
6059 checkGLcall("glGenTextures");
6060 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6061 checkGLcall("glBindTexture");
6062 /* Copy the bitmap memory into the cursor texture */
6063 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6064 HeapFree(GetProcessHeap(), 0, mem);
6065 checkGLcall("glTexImage2D");
6067 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6069 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6070 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6075 context_release(context);
6079 FIXME("A cursor texture was not returned.\n");
6080 This->cursorTexture = 0;
6085 /* Draw a hardware cursor */
6086 ICONINFO cursorInfo;
6088 /* Create and clear maskBits because it is not needed for
6089 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6091 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6092 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6093 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6094 WINED3DLOCK_NO_DIRTY_UPDATE |
6095 WINED3DLOCK_READONLY
6097 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6098 pSur->currentDesc.Height);
6100 cursorInfo.fIcon = FALSE;
6101 cursorInfo.xHotspot = XHotSpot;
6102 cursorInfo.yHotspot = YHotSpot;
6103 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6105 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6106 1, 32, lockedRect.pBits);
6107 IWineD3DSurface_UnlockRect(pCursorBitmap);
6108 /* Create our cursor and clean up. */
6109 cursor = CreateIconIndirect(&cursorInfo);
6111 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6112 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6113 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6114 This->hardwareCursor = cursor;
6115 HeapFree(GetProcessHeap(), 0, maskBits);
6119 This->xHotSpot = XHotSpot;
6120 This->yHotSpot = YHotSpot;
6124 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6126 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6128 This->xScreenSpace = XScreenSpace;
6129 This->yScreenSpace = YScreenSpace;
6135 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6137 BOOL oldVisible = This->bCursorVisible;
6140 TRACE("(%p) : visible(%d)\n", This, bShow);
6143 * When ShowCursor is first called it should make the cursor appear at the OS's last
6144 * known cursor position. Because of this, some applications just repetitively call
6145 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6148 This->xScreenSpace = pt.x;
6149 This->yScreenSpace = pt.y;
6151 if (This->haveHardwareCursor) {
6152 This->bCursorVisible = bShow;
6154 SetCursor(This->hardwareCursor);
6160 if (This->cursorTexture)
6161 This->bCursorVisible = bShow;
6167 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6168 TRACE("checking resource %p for eviction\n", resource);
6169 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6170 TRACE("Evicting %p\n", resource);
6171 IWineD3DResource_UnLoad(resource);
6173 IWineD3DResource_Release(resource);
6177 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6179 TRACE("iface %p.\n", iface);
6181 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6185 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6187 IWineD3DDeviceImpl *device = surface->resource.device;
6188 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6190 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6191 if(surface->Flags & SFLAG_DIBSECTION) {
6192 /* Release the DC */
6193 SelectObject(surface->hDC, surface->dib.holdbitmap);
6194 DeleteDC(surface->hDC);
6195 /* Release the DIB section */
6196 DeleteObject(surface->dib.DIBsection);
6197 surface->dib.bitmap_data = NULL;
6198 surface->resource.allocatedMemory = NULL;
6199 surface->Flags &= ~SFLAG_DIBSECTION;
6201 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6202 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6203 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6204 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6206 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6207 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6209 surface->pow2Width = surface->pow2Height = 1;
6210 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6211 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6214 if (surface->texture_name)
6216 struct wined3d_context *context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
6218 glDeleteTextures(1, &surface->texture_name);
6220 context_release(context);
6221 surface->texture_name = 0;
6222 surface->Flags &= ~SFLAG_CLIENT;
6224 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6225 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6226 surface->Flags |= SFLAG_NONPOW2;
6228 surface->Flags &= ~SFLAG_NONPOW2;
6230 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6231 surface->resource.allocatedMemory = NULL;
6232 surface->resource.heapMemory = NULL;
6233 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6235 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6237 if(!surface_init_sysmem((IWineD3DSurface *) surface))
6239 return E_OUTOFMEMORY;
6244 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6245 TRACE("Unloading resource %p\n", resource);
6246 IWineD3DResource_UnLoad(resource);
6247 IWineD3DResource_Release(resource);
6251 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6254 WINED3DDISPLAYMODE m;
6257 /* All Windowed modes are supported, as is leaving the current mode */
6258 if(pp->Windowed) return TRUE;
6259 if(!pp->BackBufferWidth) return TRUE;
6260 if(!pp->BackBufferHeight) return TRUE;
6262 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6263 for(i = 0; i < count; i++) {
6264 memset(&m, 0, sizeof(m));
6265 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6267 ERR("EnumAdapterModes failed\n");
6269 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6270 /* Mode found, it is supported */
6274 /* Mode not found -> not supported */
6278 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6281 const struct wined3d_gl_info *gl_info;
6282 struct wined3d_context *context;
6283 IWineD3DBaseShaderImpl *shader;
6285 context = context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6286 gl_info = context->gl_info;
6288 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6289 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6290 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6294 if(This->depth_blt_texture) {
6295 glDeleteTextures(1, &This->depth_blt_texture);
6296 This->depth_blt_texture = 0;
6298 if (This->depth_blt_rb) {
6299 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6300 This->depth_blt_rb = 0;
6301 This->depth_blt_rb_w = 0;
6302 This->depth_blt_rb_h = 0;
6306 This->blitter->free_private(iface);
6307 This->frag_pipe->free_private(iface);
6308 This->shader_backend->shader_free_private(iface);
6309 destroy_dummy_textures(This, gl_info);
6311 context_release(context);
6313 while (This->numContexts)
6315 context_destroy(This, This->contexts[0]);
6317 HeapFree(GetProcessHeap(), 0, swapchain->context);
6318 swapchain->context = NULL;
6319 swapchain->num_contexts = 0;
6322 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6325 struct wined3d_context *context;
6327 IWineD3DSurfaceImpl *target;
6329 /* Recreate the primary swapchain's context */
6330 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6331 if (!swapchain->context)
6333 ERR("Failed to allocate memory for swapchain context array.\n");
6334 return E_OUTOFMEMORY;
6337 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6338 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6340 WARN("Failed to create context.\n");
6341 HeapFree(GetProcessHeap(), 0, swapchain->context);
6345 swapchain->context[0] = context;
6346 swapchain->num_contexts = 1;
6347 create_dummy_textures(This);
6348 context_release(context);
6350 hr = This->shader_backend->shader_alloc_private(iface);
6353 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6357 hr = This->frag_pipe->alloc_private(iface);
6360 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6361 This->shader_backend->shader_free_private(iface);
6365 hr = This->blitter->alloc_private(iface);
6368 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6369 This->frag_pipe->free_private(iface);
6370 This->shader_backend->shader_free_private(iface);
6377 context_acquire(This, NULL, CTXUSAGE_RESOURCELOAD);
6378 destroy_dummy_textures(This, context->gl_info);
6379 context_release(context);
6380 context_destroy(This, context);
6381 HeapFree(GetProcessHeap(), 0, swapchain->context);
6382 swapchain->num_contexts = 0;
6386 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6388 IWineD3DSwapChainImpl *swapchain;
6390 BOOL DisplayModeChanged = FALSE;
6391 WINED3DDISPLAYMODE mode;
6392 TRACE("(%p)\n", This);
6394 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6396 ERR("Failed to get the first implicit swapchain\n");
6400 if(!is_display_mode_supported(This, pPresentationParameters)) {
6401 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6402 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6403 pPresentationParameters->BackBufferHeight);
6404 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6405 return WINED3DERR_INVALIDCALL;
6408 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6409 * on an existing gl context, so there's no real need for recreation.
6411 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6413 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6415 TRACE("New params:\n");
6416 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6417 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6418 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6419 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6420 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6421 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6422 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6423 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6424 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6425 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6426 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6427 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6428 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6430 /* No special treatment of these parameters. Just store them */
6431 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6432 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6433 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6434 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6436 /* What to do about these? */
6437 if(pPresentationParameters->BackBufferCount != 0 &&
6438 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6439 ERR("Cannot change the back buffer count yet\n");
6441 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6442 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6443 ERR("Cannot change the back buffer format yet\n");
6445 if(pPresentationParameters->hDeviceWindow != NULL &&
6446 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6447 ERR("Cannot change the device window yet\n");
6449 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6453 TRACE("Creating the depth stencil buffer\n");
6455 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6457 pPresentationParameters->BackBufferWidth,
6458 pPresentationParameters->BackBufferHeight,
6459 pPresentationParameters->AutoDepthStencilFormat,
6460 pPresentationParameters->MultiSampleType,
6461 pPresentationParameters->MultiSampleQuality,
6463 (IWineD3DSurface **)&This->auto_depth_stencil);
6466 ERR("Failed to create the depth stencil buffer\n");
6467 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6468 return WINED3DERR_INVALIDCALL;
6472 if (This->onscreen_depth_stencil)
6474 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6475 This->onscreen_depth_stencil = NULL;
6478 /* Reset the depth stencil */
6479 if (pPresentationParameters->EnableAutoDepthStencil)
6480 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6482 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6484 TRACE("Resetting stateblock\n");
6485 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6486 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6488 delete_opengl_contexts(iface, swapchain);
6490 if(pPresentationParameters->Windowed) {
6491 mode.Width = swapchain->orig_width;
6492 mode.Height = swapchain->orig_height;
6493 mode.RefreshRate = 0;
6494 mode.Format = swapchain->presentParms.BackBufferFormat;
6496 mode.Width = pPresentationParameters->BackBufferWidth;
6497 mode.Height = pPresentationParameters->BackBufferHeight;
6498 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6499 mode.Format = swapchain->presentParms.BackBufferFormat;
6502 /* Should Width == 800 && Height == 0 set 800x600? */
6503 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6504 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6505 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6509 if(!pPresentationParameters->Windowed) {
6510 DisplayModeChanged = TRUE;
6512 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6513 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6515 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6518 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6522 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6524 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6527 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6531 if (This->auto_depth_stencil)
6533 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6536 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6542 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6543 || DisplayModeChanged)
6545 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6547 if (!pPresentationParameters->Windowed)
6549 if(swapchain->presentParms.Windowed) {
6550 /* switch from windowed to fs */
6551 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6552 pPresentationParameters->BackBufferHeight);
6554 /* Fullscreen -> fullscreen mode change */
6555 MoveWindow(swapchain->device_window, 0, 0,
6556 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6560 else if (!swapchain->presentParms.Windowed)
6562 /* Fullscreen -> windowed switch */
6563 swapchain_restore_fullscreen_window(swapchain);
6565 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6566 } else if(!pPresentationParameters->Windowed) {
6567 DWORD style = This->style, exStyle = This->exStyle;
6568 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6569 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6570 * Reset to clear up their mess. Guild Wars also loses the device during that.
6574 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6575 pPresentationParameters->BackBufferHeight);
6576 This->style = style;
6577 This->exStyle = exStyle;
6580 /* Note: No parent needed for initial internal stateblock */
6581 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6582 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6583 else TRACE("Created stateblock %p\n", This->stateBlock);
6584 This->updateStateBlock = This->stateBlock;
6585 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6587 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6589 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6592 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6595 GetClientRect(swapchain->win_handle, &client_rect);
6597 if(!swapchain->presentParms.BackBufferCount)
6599 TRACE("Single buffered rendering\n");
6600 swapchain->render_to_fbo = FALSE;
6602 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6603 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6605 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6606 swapchain->presentParms.BackBufferWidth,
6607 swapchain->presentParms.BackBufferHeight,
6608 client_rect.right, client_rect.bottom);
6609 swapchain->render_to_fbo = TRUE;
6613 TRACE("Rendering directly to GL_BACK\n");
6614 swapchain->render_to_fbo = FALSE;
6618 hr = create_primary_opengl_context(iface, swapchain);
6619 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6621 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6627 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6629 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6631 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6637 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6639 TRACE("(%p) : pParameters %p\n", This, pParameters);
6641 *pParameters = This->createParms;
6645 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6646 IWineD3DSwapChain *swapchain;
6648 TRACE("Relaying to swapchain\n");
6650 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6651 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6652 IWineD3DSwapChain_Release(swapchain);
6656 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6657 IWineD3DSwapChain *swapchain;
6659 TRACE("Relaying to swapchain\n");
6661 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6662 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6663 IWineD3DSwapChain_Release(swapchain);
6668 /** ********************************************************
6669 * Notification functions
6670 ** ********************************************************/
6671 /** This function must be called in the release of a resource when ref == 0,
6672 * the contents of resource must still be correct,
6673 * any handles to other resource held by the caller must be closed
6674 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6675 *****************************************************/
6676 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6678 TRACE("(%p) : Adding resource %p\n", This, resource);
6680 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6683 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6685 TRACE("(%p) : Removing resource %p\n", This, resource);
6687 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6690 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6692 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6695 TRACE("(%p) : resource %p\n", This, resource);
6697 context_resource_released((IWineD3DDevice *)This, resource, type);
6700 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6701 case WINED3DRTYPE_SURFACE: {
6704 if (This->d3d_initialized)
6706 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6708 if (This->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6709 This->render_targets[i] = NULL;
6711 if (This->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6712 This->depth_stencil = NULL;
6717 case WINED3DRTYPE_TEXTURE:
6718 case WINED3DRTYPE_CUBETEXTURE:
6719 case WINED3DRTYPE_VOLUMETEXTURE:
6720 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6721 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6722 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6723 This->stateBlock->textures[counter] = NULL;
6725 if (This->updateStateBlock != This->stateBlock ){
6726 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6727 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6728 This->updateStateBlock->textures[counter] = NULL;
6733 case WINED3DRTYPE_VOLUME:
6734 /* TODO: nothing really? */
6736 case WINED3DRTYPE_BUFFER:
6739 TRACE("Cleaning up stream pointers\n");
6741 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6742 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6743 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6745 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6746 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6747 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6748 This->updateStateBlock->streamSource[streamNumber] = 0;
6749 /* Set changed flag? */
6752 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) */
6753 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6754 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6755 This->stateBlock->streamSource[streamNumber] = 0;
6760 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6761 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6762 This->updateStateBlock->pIndexData = NULL;
6765 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6766 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6767 This->stateBlock->pIndexData = NULL;
6774 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6779 /* Remove the resource from the resourceStore */
6780 device_resource_remove(This, resource);
6782 TRACE("Resource released\n");
6786 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6788 IWineD3DResourceImpl *resource, *cursor;
6790 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6792 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6793 TRACE("enumerating resource %p\n", resource);
6794 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6795 ret = pCallback((IWineD3DResource *) resource, pData);
6796 if(ret == S_FALSE) {
6797 TRACE("Canceling enumeration\n");
6804 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6807 IWineD3DResourceImpl *resource;
6809 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6811 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6812 if (type == WINED3DRTYPE_SURFACE)
6814 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6816 TRACE("Found surface %p for dc %p.\n", resource, dc);
6817 *surface = (IWineD3DSurface *)resource;
6823 return WINED3DERR_INVALIDCALL;
6826 /**********************************************************
6827 * IWineD3DDevice VTbl follows
6828 **********************************************************/
6830 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6832 /*** IUnknown methods ***/
6833 IWineD3DDeviceImpl_QueryInterface,
6834 IWineD3DDeviceImpl_AddRef,
6835 IWineD3DDeviceImpl_Release,
6836 /*** IWineD3DDevice methods ***/
6837 IWineD3DDeviceImpl_GetParent,
6838 /*** Creation methods**/
6839 IWineD3DDeviceImpl_CreateBuffer,
6840 IWineD3DDeviceImpl_CreateVertexBuffer,
6841 IWineD3DDeviceImpl_CreateIndexBuffer,
6842 IWineD3DDeviceImpl_CreateStateBlock,
6843 IWineD3DDeviceImpl_CreateSurface,
6844 IWineD3DDeviceImpl_CreateRendertargetView,
6845 IWineD3DDeviceImpl_CreateTexture,
6846 IWineD3DDeviceImpl_CreateVolumeTexture,
6847 IWineD3DDeviceImpl_CreateVolume,
6848 IWineD3DDeviceImpl_CreateCubeTexture,
6849 IWineD3DDeviceImpl_CreateQuery,
6850 IWineD3DDeviceImpl_CreateSwapChain,
6851 IWineD3DDeviceImpl_CreateVertexDeclaration,
6852 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6853 IWineD3DDeviceImpl_CreateVertexShader,
6854 IWineD3DDeviceImpl_CreateGeometryShader,
6855 IWineD3DDeviceImpl_CreatePixelShader,
6856 IWineD3DDeviceImpl_CreatePalette,
6857 /*** Odd functions **/
6858 IWineD3DDeviceImpl_Init3D,
6859 IWineD3DDeviceImpl_InitGDI,
6860 IWineD3DDeviceImpl_Uninit3D,
6861 IWineD3DDeviceImpl_UninitGDI,
6862 IWineD3DDeviceImpl_SetMultithreaded,
6863 IWineD3DDeviceImpl_EvictManagedResources,
6864 IWineD3DDeviceImpl_GetAvailableTextureMem,
6865 IWineD3DDeviceImpl_GetBackBuffer,
6866 IWineD3DDeviceImpl_GetCreationParameters,
6867 IWineD3DDeviceImpl_GetDeviceCaps,
6868 IWineD3DDeviceImpl_GetDirect3D,
6869 IWineD3DDeviceImpl_GetDisplayMode,
6870 IWineD3DDeviceImpl_SetDisplayMode,
6871 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6872 IWineD3DDeviceImpl_GetRasterStatus,
6873 IWineD3DDeviceImpl_GetSwapChain,
6874 IWineD3DDeviceImpl_Reset,
6875 IWineD3DDeviceImpl_SetDialogBoxMode,
6876 IWineD3DDeviceImpl_SetCursorProperties,
6877 IWineD3DDeviceImpl_SetCursorPosition,
6878 IWineD3DDeviceImpl_ShowCursor,
6879 /*** Getters and setters **/
6880 IWineD3DDeviceImpl_SetClipPlane,
6881 IWineD3DDeviceImpl_GetClipPlane,
6882 IWineD3DDeviceImpl_SetClipStatus,
6883 IWineD3DDeviceImpl_GetClipStatus,
6884 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6885 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6886 IWineD3DDeviceImpl_SetDepthStencilSurface,
6887 IWineD3DDeviceImpl_GetDepthStencilSurface,
6888 IWineD3DDeviceImpl_SetGammaRamp,
6889 IWineD3DDeviceImpl_GetGammaRamp,
6890 IWineD3DDeviceImpl_SetIndexBuffer,
6891 IWineD3DDeviceImpl_GetIndexBuffer,
6892 IWineD3DDeviceImpl_SetBaseVertexIndex,
6893 IWineD3DDeviceImpl_GetBaseVertexIndex,
6894 IWineD3DDeviceImpl_SetLight,
6895 IWineD3DDeviceImpl_GetLight,
6896 IWineD3DDeviceImpl_SetLightEnable,
6897 IWineD3DDeviceImpl_GetLightEnable,
6898 IWineD3DDeviceImpl_SetMaterial,
6899 IWineD3DDeviceImpl_GetMaterial,
6900 IWineD3DDeviceImpl_SetNPatchMode,
6901 IWineD3DDeviceImpl_GetNPatchMode,
6902 IWineD3DDeviceImpl_SetPaletteEntries,
6903 IWineD3DDeviceImpl_GetPaletteEntries,
6904 IWineD3DDeviceImpl_SetPixelShader,
6905 IWineD3DDeviceImpl_GetPixelShader,
6906 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6907 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6908 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6909 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6910 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6911 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6912 IWineD3DDeviceImpl_SetRenderState,
6913 IWineD3DDeviceImpl_GetRenderState,
6914 IWineD3DDeviceImpl_SetRenderTarget,
6915 IWineD3DDeviceImpl_GetRenderTarget,
6916 IWineD3DDeviceImpl_SetFrontBackBuffers,
6917 IWineD3DDeviceImpl_SetSamplerState,
6918 IWineD3DDeviceImpl_GetSamplerState,
6919 IWineD3DDeviceImpl_SetScissorRect,
6920 IWineD3DDeviceImpl_GetScissorRect,
6921 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6922 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6923 IWineD3DDeviceImpl_SetStreamSource,
6924 IWineD3DDeviceImpl_GetStreamSource,
6925 IWineD3DDeviceImpl_SetStreamSourceFreq,
6926 IWineD3DDeviceImpl_GetStreamSourceFreq,
6927 IWineD3DDeviceImpl_SetTexture,
6928 IWineD3DDeviceImpl_GetTexture,
6929 IWineD3DDeviceImpl_SetTextureStageState,
6930 IWineD3DDeviceImpl_GetTextureStageState,
6931 IWineD3DDeviceImpl_SetTransform,
6932 IWineD3DDeviceImpl_GetTransform,
6933 IWineD3DDeviceImpl_SetVertexDeclaration,
6934 IWineD3DDeviceImpl_GetVertexDeclaration,
6935 IWineD3DDeviceImpl_SetVertexShader,
6936 IWineD3DDeviceImpl_GetVertexShader,
6937 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6938 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6939 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6940 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6941 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6942 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6943 IWineD3DDeviceImpl_SetViewport,
6944 IWineD3DDeviceImpl_GetViewport,
6945 IWineD3DDeviceImpl_MultiplyTransform,
6946 IWineD3DDeviceImpl_ValidateDevice,
6947 IWineD3DDeviceImpl_ProcessVertices,
6948 /*** State block ***/
6949 IWineD3DDeviceImpl_BeginStateBlock,
6950 IWineD3DDeviceImpl_EndStateBlock,
6951 /*** Scene management ***/
6952 IWineD3DDeviceImpl_BeginScene,
6953 IWineD3DDeviceImpl_EndScene,
6954 IWineD3DDeviceImpl_Present,
6955 IWineD3DDeviceImpl_Clear,
6956 IWineD3DDeviceImpl_ClearRendertargetView,
6958 IWineD3DDeviceImpl_SetPrimitiveType,
6959 IWineD3DDeviceImpl_GetPrimitiveType,
6960 IWineD3DDeviceImpl_DrawPrimitive,
6961 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6962 IWineD3DDeviceImpl_DrawPrimitiveUP,
6963 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6964 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6965 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6966 IWineD3DDeviceImpl_DrawRectPatch,
6967 IWineD3DDeviceImpl_DrawTriPatch,
6968 IWineD3DDeviceImpl_DeletePatch,
6969 IWineD3DDeviceImpl_ColorFill,
6970 IWineD3DDeviceImpl_UpdateTexture,
6971 IWineD3DDeviceImpl_UpdateSurface,
6972 IWineD3DDeviceImpl_GetFrontBufferData,
6973 /*** object tracking ***/
6974 IWineD3DDeviceImpl_EnumResources,
6975 IWineD3DDeviceImpl_GetSurfaceFromDC,
6976 IWineD3DDeviceImpl_AcquireFocusWindow,
6977 IWineD3DDeviceImpl_ReleaseFocusWindow,
6980 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6981 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6982 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6984 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6985 const struct fragment_pipeline *fragment_pipeline;
6986 struct shader_caps shader_caps;
6987 struct fragment_caps ffp_caps;
6988 WINED3DDISPLAYMODE mode;
6992 device->lpVtbl = &IWineD3DDevice_Vtbl;
6994 device->wined3d = (IWineD3D *)wined3d;
6995 IWineD3D_AddRef(device->wined3d);
6996 device->adapter = wined3d->adapter_count ? adapter : NULL;
6997 device->parent = parent;
6998 device->device_parent = device_parent;
6999 list_init(&device->resources);
7000 list_init(&device->shaders);
7002 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
7003 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
7005 /* Get the initial screen setup for ddraw. */
7006 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
7009 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7010 IWineD3D_Release(device->wined3d);
7013 device->ddraw_width = mode.Width;
7014 device->ddraw_height = mode.Height;
7015 device->ddraw_format = mode.Format;
7017 /* Save the creation parameters. */
7018 device->createParms.AdapterOrdinal = adapter_idx;
7019 device->createParms.DeviceType = device_type;
7020 device->createParms.hFocusWindow = focus_window;
7021 device->createParms.BehaviorFlags = flags;
7023 device->devType = device_type;
7024 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7026 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7027 device->shader_backend = adapter->shader_backend;
7029 memset(&shader_caps, 0, sizeof(shader_caps));
7030 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7031 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7032 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7033 device->vs_clipping = shader_caps.VSClipping;
7035 memset(&ffp_caps, 0, sizeof(ffp_caps));
7036 fragment_pipeline = adapter->fragment_pipe;
7037 device->frag_pipe = fragment_pipeline;
7038 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7039 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7041 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7042 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7045 ERR("Failed to compile state table, hr %#x.\n", hr);
7046 IWineD3D_Release(device->wined3d);
7050 device->blitter = adapter->blitter;
7056 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7057 DWORD rep = This->StateTable[state].representative;
7058 struct wined3d_context *context;
7063 for(i = 0; i < This->numContexts; i++) {
7064 context = This->contexts[i];
7065 if(isStateDirty(context, rep)) continue;
7067 context->dirtyArray[context->numDirtyEntries++] = rep;
7068 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7069 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7070 context->isStateDirty[idx] |= (1 << shift);
7074 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7076 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7077 *width = context->current_rt->pow2Width;
7078 *height = context->current_rt->pow2Height;
7081 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7083 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7084 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7085 * current context's drawable, which is the size of the back buffer of the swapchain
7086 * the active context belongs to. */
7087 *width = swapchain->presentParms.BackBufferWidth;
7088 *height = swapchain->presentParms.BackBufferHeight;
7091 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7092 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7094 if (device->filter_messages)
7096 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7097 window, message, wparam, lparam);
7098 return DefWindowProcW(window, message, wparam, lparam);
7101 if (message == WM_DESTROY)
7103 TRACE("unregister window %p.\n", window);
7104 wined3d_unregister_window(window);
7106 if (device->focus_window == window) device->focus_window = NULL;
7107 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7110 return CallWindowProcW(proc, window, message, wparam, lparam);