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 (*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],
217 &This->adapter->gl_info, &buffer_object);
219 /* Can't use vbo's if the base vertex index is negative. OpenGL doesn't accept negative offsets
220 * (or rather offsets bigger than the vbo, because the pointer is unsigned), so use system memory
221 * sources. In most sane cases the pointer - offset will still be > 0, otherwise it will wrap
222 * around to some big value. Hope that with the indices, the driver wraps it back internally. If
223 * not, drawStridedSlow is needed, including a vertex buffer path. */
224 if (This->stateBlock->loadBaseVertexIndex < 0)
226 WARN("loadBaseVertexIndex is < 0 (%d), not using vbos\n", This->stateBlock->loadBaseVertexIndex);
228 data = buffer_get_sysmem((struct wined3d_buffer *)This->stateBlock->streamSource[element->input_slot],
229 &This->adapter->gl_info);
230 if ((UINT_PTR)data < -This->stateBlock->loadBaseVertexIndex * stride)
232 FIXME("System memory vertex data load offset is negative!\n");
238 if (buffer_object) *fixup = TRUE;
239 else if (*fixup && !use_vshader
240 && (element->usage == WINED3DDECLUSAGE_COLOR
241 || element->usage == WINED3DDECLUSAGE_POSITIONT))
243 static BOOL warned = FALSE;
246 /* This may be bad with the fixed function pipeline. */
247 FIXME("Missing vbo streams with unfixed colors or transformed position, expect problems\n");
253 data += element->offset;
255 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
259 if (element->output_slot == ~0U)
261 /* TODO: Assuming vertexdeclarations are usually used with the
262 * same or a similar shader, it might be worth it to store the
263 * last used output slot and try that one first. */
264 stride_used = vshader_get_input(This->stateBlock->vertexShader,
265 element->usage, element->usage_idx, &idx);
269 idx = element->output_slot;
275 if (!element->ffp_valid)
277 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
278 debug_d3dformat(element->format_desc->format), debug_d3ddeclusage(element->usage));
283 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
289 TRACE("Load %s array %u [usage %s, usage_idx %u, "
290 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
291 use_vshader ? "shader": "fixed function", idx,
292 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
293 element->offset, stride, debug_d3dformat(element->format_desc->format), buffer_object);
295 stream_info->elements[idx].format_desc = element->format_desc;
296 stream_info->elements[idx].stride = stride;
297 stream_info->elements[idx].data = data;
298 stream_info->elements[idx].stream_idx = element->input_slot;
299 stream_info->elements[idx].buffer_object = buffer_object;
301 if (!This->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
302 && element->format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
304 stream_info->swizzle_map |= 1 << idx;
306 stream_info->use_map |= 1 << idx;
310 This->num_buffer_queries = 0;
311 if (!This->stateBlock->streamIsUP)
313 WORD map = stream_info->use_map;
315 /* PreLoad all the vertex buffers. */
316 for (i = 0; map; map >>= 1, ++i)
318 struct wined3d_stream_info_element *element;
319 struct wined3d_buffer *buffer;
320 struct wined3d_event_query *query;
322 if (!(map & 1)) continue;
324 element = &stream_info->elements[i];
325 buffer = (struct wined3d_buffer *)This->stateBlock->streamSource[element->stream_idx];
326 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)buffer);
328 /* If PreLoad dropped the buffer object, update the stream info. */
329 if (buffer->buffer_object != element->buffer_object)
331 element->buffer_object = 0;
332 element->data = buffer_get_sysmem(buffer, &This->adapter->gl_info) + (ptrdiff_t)element->data;
335 query = ((struct wined3d_buffer *) buffer)->query;
338 This->buffer_queries[This->num_buffer_queries++] = query;
344 static void stream_info_element_from_strided(const struct wined3d_gl_info *gl_info,
345 const struct WineDirect3DStridedData *strided, struct wined3d_stream_info_element *e)
347 const struct wined3d_format_desc *format_desc = getFormatDescEntry(strided->format, gl_info);
348 e->format_desc = format_desc;
349 e->stride = strided->dwStride;
350 e->data = strided->lpData;
352 e->buffer_object = 0;
355 static void device_stream_info_from_strided(const struct wined3d_gl_info *gl_info,
356 const struct WineDirect3DVertexStridedData *strided, struct wined3d_stream_info *stream_info)
360 memset(stream_info, 0, sizeof(*stream_info));
362 if (strided->position.lpData)
363 stream_info_element_from_strided(gl_info, &strided->position, &stream_info->elements[WINED3D_FFP_POSITION]);
364 if (strided->normal.lpData)
365 stream_info_element_from_strided(gl_info, &strided->normal, &stream_info->elements[WINED3D_FFP_NORMAL]);
366 if (strided->diffuse.lpData)
367 stream_info_element_from_strided(gl_info, &strided->diffuse, &stream_info->elements[WINED3D_FFP_DIFFUSE]);
368 if (strided->specular.lpData)
369 stream_info_element_from_strided(gl_info, &strided->specular, &stream_info->elements[WINED3D_FFP_SPECULAR]);
371 for (i = 0; i < WINED3DDP_MAXTEXCOORD; ++i)
373 if (strided->texCoords[i].lpData)
374 stream_info_element_from_strided(gl_info, &strided->texCoords[i],
375 &stream_info->elements[WINED3D_FFP_TEXCOORD0 + i]);
378 stream_info->position_transformed = strided->position_transformed;
380 for (i = 0; i < sizeof(stream_info->elements) / sizeof(*stream_info->elements); ++i)
382 if (!stream_info->elements[i].format_desc) continue;
384 if (!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
385 && stream_info->elements[i].format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
387 stream_info->swizzle_map |= 1 << i;
389 stream_info->use_map |= 1 << i;
393 static void device_trace_strided_stream_info(const struct wined3d_stream_info *stream_info)
395 TRACE("Strided Data:\n");
396 TRACE_STRIDED(stream_info, WINED3D_FFP_POSITION);
397 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDWEIGHT);
398 TRACE_STRIDED(stream_info, WINED3D_FFP_BLENDINDICES);
399 TRACE_STRIDED(stream_info, WINED3D_FFP_NORMAL);
400 TRACE_STRIDED(stream_info, WINED3D_FFP_PSIZE);
401 TRACE_STRIDED(stream_info, WINED3D_FFP_DIFFUSE);
402 TRACE_STRIDED(stream_info, WINED3D_FFP_SPECULAR);
403 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD0);
404 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD1);
405 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD2);
406 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD3);
407 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD4);
408 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD5);
409 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD6);
410 TRACE_STRIDED(stream_info, WINED3D_FFP_TEXCOORD7);
413 /* Context activation is done by the caller. */
414 void device_update_stream_info(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
416 struct wined3d_stream_info *stream_info = &device->strided_streams;
417 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
418 BOOL vs = stateblock->vertexShader && device->vs_selected_mode != SHADER_NONE;
421 if (device->up_strided)
423 /* Note: this is a ddraw fixed-function code path. */
424 TRACE("=============================== Strided Input ================================\n");
425 device_stream_info_from_strided(gl_info, device->up_strided, stream_info);
426 if (TRACE_ON(d3d)) device_trace_strided_stream_info(stream_info);
430 TRACE("============================= Vertex Declaration =============================\n");
431 device_stream_info_from_declaration(device, vs, stream_info, &fixup);
434 if (vs && !stream_info->position_transformed)
436 if (((IWineD3DVertexDeclarationImpl *)stateblock->vertexDecl)->half_float_conv_needed && !fixup)
438 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
439 device->useDrawStridedSlow = TRUE;
443 device->useDrawStridedSlow = FALSE;
448 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
449 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
450 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
452 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !fixup)
454 device->useDrawStridedSlow = TRUE;
458 device->useDrawStridedSlow = FALSE;
463 static void device_preload_texture(IWineD3DStateBlockImpl *stateblock, unsigned int idx)
465 IWineD3DBaseTextureImpl *texture;
466 enum WINED3DSRGB srgb;
468 if (!(texture = (IWineD3DBaseTextureImpl *)stateblock->textures[idx])) return;
469 srgb = stateblock->samplerState[idx][WINED3DSAMP_SRGBTEXTURE] ? SRGB_SRGB : SRGB_RGB;
470 texture->baseTexture.internal_preload((IWineD3DBaseTexture *)texture, srgb);
473 void device_preload_textures(IWineD3DDeviceImpl *device)
475 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
478 if (use_vs(stateblock))
480 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
482 if (((IWineD3DBaseShaderImpl *)stateblock->vertexShader)->baseShader.reg_maps.sampler_type[i])
483 device_preload_texture(stateblock, MAX_FRAGMENT_SAMPLERS + i);
487 if (use_ps(stateblock))
489 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
491 if (((IWineD3DBaseShaderImpl *)stateblock->pixelShader)->baseShader.reg_maps.sampler_type[i])
492 device_preload_texture(stateblock, i);
497 WORD ffu_map = device->fixed_function_usage_map;
499 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
502 device_preload_texture(stateblock, i);
507 BOOL device_context_add(IWineD3DDeviceImpl *device, struct wined3d_context *context)
509 struct wined3d_context **new_array;
511 TRACE("Adding context %p.\n", context);
513 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
514 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, sizeof(*new_array) * (device->numContexts + 1));
518 ERR("Failed to grow the context array.\n");
522 new_array[device->numContexts++] = context;
523 device->contexts = new_array;
527 void device_context_remove(IWineD3DDeviceImpl *device, struct wined3d_context *context)
529 struct wined3d_context **new_array;
533 TRACE("Removing context %p.\n", context);
535 for (i = 0; i < device->numContexts; ++i)
537 if (device->contexts[i] == context)
546 ERR("Context %p doesn't exist in context array.\n", context);
550 if (!--device->numContexts)
552 HeapFree(GetProcessHeap(), 0, device->contexts);
553 device->contexts = NULL;
557 memmove(&device->contexts[i], &device->contexts[i + 1], (device->numContexts - i) * sizeof(*device->contexts));
558 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->numContexts * sizeof(*device->contexts));
561 ERR("Failed to shrink context array. Oh well.\n");
565 device->contexts = new_array;
568 void device_get_draw_rect(IWineD3DDeviceImpl *device, RECT *rect)
570 IWineD3DStateBlockImpl *stateblock = device->stateBlock;
571 WINED3DVIEWPORT *vp = &stateblock->viewport;
573 SetRect(rect, vp->X, vp->Y, vp->X + vp->Width, vp->Y + vp->Height);
575 if (stateblock->renderState[WINED3DRS_SCISSORTESTENABLE])
577 IntersectRect(rect, rect, &stateblock->scissorRect);
581 void device_switch_onscreen_ds(IWineD3DDeviceImpl *device,
582 struct wined3d_context *context, IWineD3DSurfaceImpl *depth_stencil)
584 if (device->onscreen_depth_stencil)
586 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_DS_OFFSCREEN);
587 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_DS_OFFSCREEN,
588 device->onscreen_depth_stencil->ds_current_size.cx,
589 device->onscreen_depth_stencil->ds_current_size.cy);
590 IWineD3DSurface_Release((IWineD3DSurface *)device->onscreen_depth_stencil);
592 device->onscreen_depth_stencil = depth_stencil;
593 IWineD3DSurface_AddRef((IWineD3DSurface *)device->onscreen_depth_stencil);
596 /**********************************************************
597 * IUnknown parts follows
598 **********************************************************/
600 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
604 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
605 if (IsEqualGUID(riid, &IID_IUnknown)
606 || IsEqualGUID(riid, &IID_IWineD3DBase)
607 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
608 IUnknown_AddRef(iface);
613 return E_NOINTERFACE;
616 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
618 ULONG refCount = InterlockedIncrement(&This->ref);
620 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
624 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
626 ULONG refCount = InterlockedDecrement(&This->ref);
628 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
633 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
634 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
635 This->multistate_funcs[i] = NULL;
638 /* TODO: Clean up all the surfaces and textures! */
639 /* NOTE: You must release the parent if the object was created via a callback
640 ** ***************************/
642 if (!list_empty(&This->resources))
644 IWineD3DResourceImpl *resource;
645 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
647 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
649 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
650 FIXME("Leftover resource %p with type %s (%#x).\n",
651 resource, debug_d3dresourcetype(type), type);
655 if(This->contexts) ERR("Context array not freed!\n");
656 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
657 This->haveHardwareCursor = FALSE;
659 IWineD3D_Release(This->wined3d);
660 This->wined3d = NULL;
661 HeapFree(GetProcessHeap(), 0, This);
662 TRACE("Freed device %p\n", This);
668 /**********************************************************
669 * IWineD3DDevice implementation follows
670 **********************************************************/
671 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
673 *pParent = This->parent;
674 IUnknown_AddRef(This->parent);
678 static HRESULT WINAPI IWineD3DDeviceImpl_CreateBuffer(IWineD3DDevice *iface, struct wined3d_buffer_desc *desc,
679 const void *data, IUnknown *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DBuffer **buffer)
681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
682 struct wined3d_buffer *object;
685 TRACE("iface %p, desc %p, data %p, parent %p, buffer %p\n", iface, desc, data, parent, buffer);
687 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
690 ERR("Failed to allocate memory\n");
691 return E_OUTOFMEMORY;
694 FIXME("Ignoring access flags (pool)\n");
696 hr = buffer_init(object, This, desc->byte_width, desc->usage, WINED3DFMT_UNKNOWN,
697 WINED3DPOOL_MANAGED, GL_ARRAY_BUFFER_ARB, data, parent, parent_ops);
700 WARN("Failed to initialize buffer, hr %#x.\n", hr);
701 HeapFree(GetProcessHeap(), 0, object);
704 object->desc = *desc;
706 TRACE("Created buffer %p.\n", object);
708 *buffer = (IWineD3DBuffer *)object;
713 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface,
714 UINT Size, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppVertexBuffer,
715 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
718 struct wined3d_buffer *object;
721 TRACE("iface %p, size %u, usage %#x, pool %#x, buffer %p, parent %p, parent_ops %p.\n",
722 iface, Size, Usage, Pool, ppVertexBuffer, parent, parent_ops);
724 if (Pool == WINED3DPOOL_SCRATCH)
726 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
727 * anyway, SCRATCH vertex buffers aren't usable anywhere
729 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
730 *ppVertexBuffer = NULL;
731 return WINED3DERR_INVALIDCALL;
734 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
737 ERR("Out of memory\n");
738 *ppVertexBuffer = NULL;
739 return WINED3DERR_OUTOFVIDEOMEMORY;
742 hr = buffer_init(object, This, Size, Usage, WINED3DFMT_VERTEXDATA,
743 Pool, GL_ARRAY_BUFFER_ARB, NULL, parent, parent_ops);
746 WARN("Failed to initialize buffer, hr %#x.\n", hr);
747 HeapFree(GetProcessHeap(), 0, object);
751 TRACE("Created buffer %p.\n", object);
752 *ppVertexBuffer = (IWineD3DBuffer *)object;
757 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface,
758 UINT Length, DWORD Usage, WINED3DPOOL Pool, IWineD3DBuffer **ppIndexBuffer,
759 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
762 struct wined3d_buffer *object;
765 TRACE("(%p) Creating index buffer\n", This);
767 /* Allocate the storage for the device */
768 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
771 ERR("Out of memory\n");
772 *ppIndexBuffer = NULL;
773 return WINED3DERR_OUTOFVIDEOMEMORY;
776 hr = buffer_init(object, This, Length, Usage | WINED3DUSAGE_STATICDECL,
777 WINED3DFMT_UNKNOWN, Pool, GL_ELEMENT_ARRAY_BUFFER_ARB, NULL,
781 WARN("Failed to initialize buffer, hr %#x\n", hr);
782 HeapFree(GetProcessHeap(), 0, object);
786 TRACE("Created buffer %p.\n", object);
788 *ppIndexBuffer = (IWineD3DBuffer *) object;
793 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice *iface,
794 WINED3DSTATEBLOCKTYPE type, IWineD3DStateBlock **stateblock, IUnknown *parent)
796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
797 IWineD3DStateBlockImpl *object;
800 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
803 ERR("Failed to allocate stateblock memory.\n");
804 return E_OUTOFMEMORY;
807 hr = stateblock_init(object, This, type);
810 WARN("Failed to initialize stateblock, hr %#x.\n", hr);
811 HeapFree(GetProcessHeap(), 0, object);
815 TRACE("Created stateblock %p.\n", object);
816 *stateblock = (IWineD3DStateBlock *)object;
821 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height,
822 WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,
823 DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality,
824 WINED3DSURFTYPE Impl, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
827 IWineD3DSurfaceImpl *object;
830 TRACE("iface %p, width %u, height %u, format %s (%#x), lockable %#x, discard %#x, level %u\n",
831 iface, Width, Height, debug_d3dformat(Format), Format, Lockable, Discard, Level);
832 TRACE("surface %p, usage %s (%#x), pool %s (%#x), multisample_type %#x, multisample_quality %u\n",
833 ppSurface, debug_d3dusage(Usage), Usage, debug_d3dpool(Pool), Pool, MultiSample, MultisampleQuality);
834 TRACE("surface_type %#x, parent %p, parent_ops %p.\n", Impl, parent, parent_ops);
836 if (Impl == SURFACE_OPENGL && !This->adapter)
838 ERR("OpenGL surfaces are not available without OpenGL.\n");
839 return WINED3DERR_NOTAVAILABLE;
842 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
845 ERR("Failed to allocate surface memory.\n");
846 return WINED3DERR_OUTOFVIDEOMEMORY;
849 hr = surface_init(object, Impl, This->surface_alignment, Width, Height, Level, Lockable,
850 Discard, MultiSample, MultisampleQuality, This, Usage, Format, Pool, parent, parent_ops);
853 WARN("Failed to initialize surface, returning %#x.\n", hr);
854 HeapFree(GetProcessHeap(), 0, object);
858 TRACE("(%p) : Created surface %p\n", This, object);
860 *ppSurface = (IWineD3DSurface *)object;
865 static HRESULT WINAPI IWineD3DDeviceImpl_CreateRendertargetView(IWineD3DDevice *iface,
866 IWineD3DResource *resource, IUnknown *parent, IWineD3DRendertargetView **rendertarget_view)
868 struct wined3d_rendertarget_view *object;
870 TRACE("iface %p, resource %p, parent %p, rendertarget_view %p.\n",
871 iface, resource, parent, rendertarget_view);
873 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
876 ERR("Failed to allocate memory\n");
877 return E_OUTOFMEMORY;
880 wined3d_rendertarget_view_init(object, resource, parent);
882 TRACE("Created render target view %p.\n", object);
883 *rendertarget_view = (IWineD3DRendertargetView *)object;
888 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface,
889 UINT Width, UINT Height, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
890 IWineD3DTexture **ppTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
893 IWineD3DTextureImpl *object;
896 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
897 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, parent %p\n",
898 Format, debug_d3dformat(Format), Pool, ppTexture, parent);
900 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
903 ERR("Out of memory\n");
905 return WINED3DERR_OUTOFVIDEOMEMORY;
908 hr = texture_init(object, Width, Height, Levels, This, Usage, Format, Pool, parent, parent_ops);
911 WARN("Failed to initialize texture, returning %#x\n", hr);
912 HeapFree(GetProcessHeap(), 0, object);
917 *ppTexture = (IWineD3DTexture *)object;
919 TRACE("(%p) : Created texture %p\n", This, object);
924 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
925 UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
926 IWineD3DVolumeTexture **ppVolumeTexture, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
929 IWineD3DVolumeTextureImpl *object;
932 TRACE("(%p) : W(%u) H(%u) D(%u), Lvl(%u) Usage(%#x), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
933 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
935 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
938 ERR("Out of memory\n");
939 *ppVolumeTexture = NULL;
940 return WINED3DERR_OUTOFVIDEOMEMORY;
943 hr = volumetexture_init(object, Width, Height, Depth, Levels, This, Usage, Format, Pool, parent, parent_ops);
946 WARN("Failed to initialize volumetexture, returning %#x\n", hr);
947 HeapFree(GetProcessHeap(), 0, object);
948 *ppVolumeTexture = NULL;
952 TRACE("(%p) : Created volume texture %p.\n", This, object);
953 *ppVolumeTexture = (IWineD3DVolumeTexture *)object;
958 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface, UINT Width, UINT Height,
959 UINT Depth, DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DVolume **ppVolume,
960 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
963 IWineD3DVolumeImpl *object;
966 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
967 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
969 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
972 ERR("Out of memory\n");
974 return WINED3DERR_OUTOFVIDEOMEMORY;
977 hr = volume_init(object, This, Width, Height, Depth, Usage, Format, Pool, parent, parent_ops);
980 WARN("Failed to initialize volume, returning %#x.\n", hr);
981 HeapFree(GetProcessHeap(), 0, object);
985 TRACE("(%p) : Created volume %p.\n", This, object);
986 *ppVolume = (IWineD3DVolume *)object;
991 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength, UINT Levels,
992 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DCubeTexture **ppCubeTexture,
993 IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
996 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
999 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1002 ERR("Out of memory\n");
1003 *ppCubeTexture = NULL;
1004 return WINED3DERR_OUTOFVIDEOMEMORY;
1007 hr = cubetexture_init(object, EdgeLength, Levels, This, Usage, Format, Pool, parent, parent_ops);
1010 WARN("Failed to initialize cubetexture, returning %#x\n", hr);
1011 HeapFree(GetProcessHeap(), 0, object);
1012 *ppCubeTexture = NULL;
1016 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1017 *ppCubeTexture = (IWineD3DCubeTexture *)object;
1022 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
1023 WINED3DQUERYTYPE type, IWineD3DQuery **query, IUnknown *parent)
1025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1026 IWineD3DQueryImpl *object;
1029 TRACE("iface %p, type %#x, query %p, parent %p.\n", iface, type, query, parent);
1031 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1034 ERR("Failed to allocate query memory.\n");
1035 return E_OUTOFMEMORY;
1038 hr = query_init(object, This, type, parent);
1041 WARN("Failed to initialize query, hr %#x.\n", hr);
1042 HeapFree(GetProcessHeap(), 0, object);
1046 TRACE("Created query %p.\n", object);
1047 *query = (IWineD3DQuery *)object;
1052 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
1053 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain,
1054 IUnknown *parent, WINED3DSURFTYPE surface_type)
1056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1057 IWineD3DSwapChainImpl *object;
1060 TRACE("iface %p, present_parameters %p, swapchain %p, parent %p, surface_type %#x.\n",
1061 iface, present_parameters, swapchain, parent, surface_type);
1063 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1066 ERR("Failed to allocate swapchain memory.\n");
1067 return E_OUTOFMEMORY;
1070 hr = swapchain_init(object, surface_type, This, present_parameters, parent);
1073 WARN("Failed to initialize swapchain, hr %#x.\n", hr);
1074 HeapFree(GetProcessHeap(), 0, object);
1078 TRACE("Created swapchain %p.\n", object);
1079 *swapchain = (IWineD3DSwapChain *)object;
1084 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1085 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1086 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1087 TRACE("(%p)\n", This);
1089 return This->NumberOfSwapChains;
1092 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1094 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1096 if(iSwapChain < This->NumberOfSwapChains) {
1097 *pSwapChain = This->swapchains[iSwapChain];
1098 IWineD3DSwapChain_AddRef(*pSwapChain);
1099 TRACE("(%p) returning %p\n", This, *pSwapChain);
1102 TRACE("Swapchain out of range\n");
1104 return WINED3DERR_INVALIDCALL;
1108 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice *iface,
1109 IWineD3DVertexDeclaration **declaration, IUnknown *parent, const struct wined3d_parent_ops *parent_ops,
1110 const WINED3DVERTEXELEMENT *elements, UINT element_count)
1112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1113 IWineD3DVertexDeclarationImpl *object = NULL;
1116 TRACE("iface %p, declaration %p, parent %p, elements %p, element_count %u.\n",
1117 iface, declaration, parent, elements, element_count);
1119 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1122 ERR("Failed to allocate vertex declaration memory.\n");
1123 return E_OUTOFMEMORY;
1126 hr = vertexdeclaration_init(object, This, elements, element_count, parent, parent_ops);
1129 WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
1130 HeapFree(GetProcessHeap(), 0, object);
1134 TRACE("Created vertex declaration %p.\n", object);
1135 *declaration = (IWineD3DVertexDeclaration *)object;
1140 struct wined3d_fvf_convert_state
1142 const struct wined3d_gl_info *gl_info;
1143 WINED3DVERTEXELEMENT *elements;
1148 static void append_decl_element(struct wined3d_fvf_convert_state *state,
1149 WINED3DFORMAT format, WINED3DDECLUSAGE usage, UINT usage_idx)
1151 WINED3DVERTEXELEMENT *elements = state->elements;
1152 const struct wined3d_format_desc *format_desc;
1153 UINT offset = state->offset;
1154 UINT idx = state->idx;
1156 elements[idx].format = format;
1157 elements[idx].input_slot = 0;
1158 elements[idx].offset = offset;
1159 elements[idx].output_slot = 0;
1160 elements[idx].method = WINED3DDECLMETHOD_DEFAULT;
1161 elements[idx].usage = usage;
1162 elements[idx].usage_idx = usage_idx;
1164 format_desc = getFormatDescEntry(format, state->gl_info);
1165 state->offset += format_desc->component_count * format_desc->component_size;
1169 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1170 DWORD fvf, WINED3DVERTEXELEMENT **ppVertexElements)
1172 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1173 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1174 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1175 BOOL has_blend_idx = has_blend &&
1176 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1177 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1178 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1179 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1180 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1181 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1182 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1184 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1185 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1186 struct wined3d_fvf_convert_state state;
1189 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1190 if (has_blend_idx) num_blends--;
1192 /* Compute declaration size */
1193 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1194 has_psize + has_diffuse + has_specular + num_textures;
1196 state.gl_info = gl_info;
1197 state.elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*state.elements));
1198 if (!state.elements) return ~0U;
1204 if (!has_blend && (fvf & WINED3DFVF_XYZRHW))
1205 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITIONT, 0);
1206 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW)
1207 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1209 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_POSITION, 0);
1212 if (has_blend && (num_blends > 0))
1214 if ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1215 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1221 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1224 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1227 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1230 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_BLENDWEIGHT, 0);
1233 ERR("Unexpected amount of blend values: %u\n", num_blends);
1240 if ((fvf & WINED3DFVF_LASTBETA_UBYTE4)
1241 || ((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2 && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1242 append_decl_element(&state, WINED3DFMT_R8G8B8A8_UINT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1243 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1244 append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_BLENDINDICES, 0);
1246 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_BLENDINDICES, 0);
1249 if (has_normal) append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_NORMAL, 0);
1250 if (has_psize) append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_PSIZE, 0);
1251 if (has_diffuse) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 0);
1252 if (has_specular) append_decl_element(&state, WINED3DFMT_B8G8R8A8_UNORM, WINED3DDECLUSAGE_COLOR, 1);
1254 for (idx = 0; idx < num_textures; ++idx)
1256 switch ((texcoords >> (idx * 2)) & 0x03)
1258 case WINED3DFVF_TEXTUREFORMAT1:
1259 append_decl_element(&state, WINED3DFMT_R32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1261 case WINED3DFVF_TEXTUREFORMAT2:
1262 append_decl_element(&state, WINED3DFMT_R32G32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1264 case WINED3DFVF_TEXTUREFORMAT3:
1265 append_decl_element(&state, WINED3DFMT_R32G32B32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1267 case WINED3DFVF_TEXTUREFORMAT4:
1268 append_decl_element(&state, WINED3DFMT_R32G32B32A32_FLOAT, WINED3DDECLUSAGE_TEXCOORD, idx);
1273 *ppVertexElements = state.elements;
1277 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice *iface,
1278 IWineD3DVertexDeclaration **declaration, IUnknown *parent,
1279 const struct wined3d_parent_ops *parent_ops, DWORD fvf)
1281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1282 WINED3DVERTEXELEMENT *elements;
1286 TRACE("iface %p, declaration %p, parent %p, fvf %#x.\n", iface, declaration, parent, fvf);
1288 size = ConvertFvfToDeclaration(This, fvf, &elements);
1289 if (size == ~0U) return E_OUTOFMEMORY;
1291 hr = IWineD3DDevice_CreateVertexDeclaration(iface, declaration, parent, parent_ops, elements, size);
1292 HeapFree(GetProcessHeap(), 0, elements);
1296 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface,
1297 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1298 IWineD3DVertexShader **ppVertexShader, IUnknown *parent,
1299 const struct wined3d_parent_ops *parent_ops)
1301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1302 IWineD3DVertexShaderImpl *object;
1305 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1308 ERR("Failed to allocate shader memory.\n");
1309 return E_OUTOFMEMORY;
1312 hr = vertexshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1315 WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
1316 HeapFree(GetProcessHeap(), 0, object);
1320 TRACE("Created vertex shader %p.\n", object);
1321 *ppVertexShader = (IWineD3DVertexShader *)object;
1326 static HRESULT WINAPI IWineD3DDeviceImpl_CreateGeometryShader(IWineD3DDevice *iface,
1327 const DWORD *byte_code, const struct wined3d_shader_signature *output_signature,
1328 IWineD3DGeometryShader **shader, IUnknown *parent,
1329 const struct wined3d_parent_ops *parent_ops)
1331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1332 struct wined3d_geometryshader *object;
1335 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1338 ERR("Failed to allocate shader memory.\n");
1339 return E_OUTOFMEMORY;
1342 hr = geometryshader_init(object, This, byte_code, output_signature, parent, parent_ops);
1345 WARN("Failed to initialize geometry shader, hr %#x.\n", hr);
1346 HeapFree(GetProcessHeap(), 0, object);
1350 TRACE("Created geometry shader %p.\n", object);
1351 *shader = (IWineD3DGeometryShader *)object;
1356 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface,
1357 const DWORD *pFunction, const struct wined3d_shader_signature *output_signature,
1358 IWineD3DPixelShader **ppPixelShader, IUnknown *parent,
1359 const struct wined3d_parent_ops *parent_ops)
1361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1362 IWineD3DPixelShaderImpl *object;
1365 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1368 ERR("Failed to allocate shader memory.\n");
1369 return E_OUTOFMEMORY;
1372 hr = pixelshader_init(object, This, pFunction, output_signature, parent, parent_ops);
1375 WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
1376 HeapFree(GetProcessHeap(), 0, object);
1380 TRACE("Created pixel shader %p.\n", object);
1381 *ppPixelShader = (IWineD3DPixelShader *)object;
1386 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1387 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1390 IWineD3DPaletteImpl *object;
1393 TRACE("iface %p, flags %#x, entries %p, palette %p, parent %p.\n",
1394 iface, Flags, PalEnt, Palette, Parent);
1396 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1399 ERR("Failed to allocate palette memory.\n");
1400 return E_OUTOFMEMORY;
1403 hr = wined3d_palette_init(object, This, Flags, PalEnt, Parent);
1406 WARN("Failed to initialize palette, hr %#x.\n", hr);
1407 HeapFree(GetProcessHeap(), 0, object);
1411 TRACE("Created palette %p.\n", object);
1412 *Palette = (IWineD3DPalette *)object;
1417 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1421 HDC dcb = NULL, dcs = NULL;
1422 WINEDDCOLORKEY colorkey;
1424 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1427 GetObjectA(hbm, sizeof(BITMAP), &bm);
1428 dcb = CreateCompatibleDC(NULL);
1430 SelectObject(dcb, hbm);
1434 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1435 * couldn't be loaded
1437 memset(&bm, 0, sizeof(bm));
1442 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *)This, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, TRUE,
1443 FALSE, 0, &This->logo_surface, 0, WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, SURFACE_OPENGL,
1444 NULL, &wined3d_null_parent_ops);
1446 ERR("Wine logo requested, but failed to create surface\n");
1451 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1452 if(FAILED(hr)) goto out;
1453 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1454 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1456 colorkey.dwColorSpaceLowValue = 0;
1457 colorkey.dwColorSpaceHighValue = 0;
1458 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1460 /* Fill the surface with a white color to show that wined3d is there */
1461 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1465 if (dcb) DeleteDC(dcb);
1466 if (hbm) DeleteObject(hbm);
1469 /* Context activation is done by the caller. */
1470 static void create_dummy_textures(IWineD3DDeviceImpl *This)
1472 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1474 /* Under DirectX you can have texture stage operations even if no texture is
1475 bound, whereas opengl will only do texture operations when a valid texture is
1476 bound. We emulate this by creating dummy textures and binding them to each
1477 texture stage, but disable all stages by default. Hence if a stage is enabled
1478 then the default texture will kick in until replaced by a SetTexture call */
1481 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1483 /* The dummy texture does not have client storage backing */
1484 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1485 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1488 for (i = 0; i < gl_info->limits.textures; ++i)
1490 GLubyte white = 255;
1492 /* Make appropriate texture active */
1493 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1494 checkGLcall("glActiveTextureARB");
1496 /* Generate an opengl texture name */
1497 glGenTextures(1, &This->dummyTextureName[i]);
1498 checkGLcall("glGenTextures");
1499 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1501 /* Generate a dummy 2d texture (not using 1d because they cause many
1502 * DRI drivers fall back to sw) */
1503 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1504 checkGLcall("glBindTexture");
1506 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1507 checkGLcall("glTexImage2D");
1510 if (gl_info->supported[APPLE_CLIENT_STORAGE])
1512 /* Reenable because if supported it is enabled by default */
1513 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1514 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1520 /* Context activation is done by the caller. */
1521 static void destroy_dummy_textures(IWineD3DDeviceImpl *device, const struct wined3d_gl_info *gl_info)
1524 glDeleteTextures(gl_info->limits.textures, device->dummyTextureName);
1525 checkGLcall("glDeleteTextures(gl_info->limits.textures, device->dummyTextureName)");
1528 memset(device->dummyTextureName, 0, gl_info->limits.textures * sizeof(*device->dummyTextureName));
1531 static HRESULT WINAPI IWineD3DDeviceImpl_AcquireFocusWindow(IWineD3DDevice *iface, HWND window)
1533 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1535 if (!wined3d_register_window(window, device))
1537 ERR("Failed to register window %p.\n", window);
1541 device->focus_window = window;
1542 SetForegroundWindow(window);
1547 static void WINAPI IWineD3DDeviceImpl_ReleaseFocusWindow(IWineD3DDevice *iface)
1549 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)iface;
1551 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1552 device->focus_window = NULL;
1555 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface,
1556 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1559 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
1560 IWineD3DSwapChainImpl *swapchain = NULL;
1561 struct wined3d_context *context;
1566 TRACE("(%p)->(%p)\n", This, pPresentationParameters);
1568 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1569 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
1571 TRACE("(%p) : Creating stateblock\n", This);
1572 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1573 hr = IWineD3DDevice_CreateStateBlock(iface,
1575 (IWineD3DStateBlock **)&This->stateBlock,
1577 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1578 WARN("Failed to create stateblock\n");
1581 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1582 This->updateStateBlock = This->stateBlock;
1583 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1585 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1586 sizeof(*This->render_targets) * gl_info->limits.buffers);
1587 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1588 sizeof(GLenum) * gl_info->limits.buffers);
1590 This->NumberOfPalettes = 1;
1591 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
1592 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
1593 ERR("Out of memory!\n");
1597 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1598 if(!This->palettes[0]) {
1599 ERR("Out of memory!\n");
1603 for (i = 0; i < 256; ++i) {
1604 This->palettes[0][i].peRed = 0xFF;
1605 This->palettes[0][i].peGreen = 0xFF;
1606 This->palettes[0][i].peBlue = 0xFF;
1607 This->palettes[0][i].peFlags = 0xFF;
1609 This->currentPalette = 0;
1611 /* Initialize the texture unit mapping to a 1:1 mapping */
1612 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1614 if (state < gl_info->limits.fragment_samplers)
1616 This->texUnitMap[state] = state;
1617 This->rev_tex_unit_map[state] = state;
1619 This->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1620 This->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1624 /* Setup the implicit swapchain. This also initializes a context. */
1625 TRACE("Creating implicit swapchain\n");
1626 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1627 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1630 WARN("Failed to create implicit swapchain\n");
1634 This->NumberOfSwapChains = 1;
1635 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1636 if(!This->swapchains) {
1637 ERR("Out of memory!\n");
1640 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1642 if (swapchain->back_buffers && swapchain->back_buffers[0])
1644 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1645 This->render_targets[0] = swapchain->back_buffers[0];
1649 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1650 This->render_targets[0] = swapchain->front_buffer;
1652 IWineD3DSurface_AddRef((IWineD3DSurface *)This->render_targets[0]);
1654 /* Depth Stencil support */
1655 This->depth_stencil = This->auto_depth_stencil;
1656 if (This->depth_stencil)
1657 IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
1659 hr = This->shader_backend->shader_alloc_private(iface);
1661 TRACE("Shader private data couldn't be allocated\n");
1664 hr = This->frag_pipe->alloc_private(iface);
1666 TRACE("Fragment pipeline private data couldn't be allocated\n");
1669 hr = This->blitter->alloc_private(iface);
1671 TRACE("Blitter private data couldn't be allocated\n");
1675 /* Set up some starting GL setup */
1677 /* Setup all the devices defaults */
1678 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1680 context = context_acquire(This, swapchain->front_buffer);
1682 create_dummy_textures(This);
1686 /* Initialize the current view state */
1687 This->view_ident = 1;
1688 This->contexts[0]->last_was_rhw = 0;
1689 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1690 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1692 switch(wined3d_settings.offscreen_rendering_mode) {
1694 This->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1697 case ORM_BACKBUFFER:
1699 if (context_get_current()->aux_buffers > 0)
1701 TRACE("Using auxilliary buffer for offscreen rendering\n");
1702 This->offscreenBuffer = GL_AUX0;
1704 TRACE("Using back buffer for offscreen rendering\n");
1705 This->offscreenBuffer = GL_BACK;
1710 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1713 context_release(context);
1715 /* Clear the screen */
1716 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1717 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1720 This->d3d_initialized = TRUE;
1722 if(wined3d_settings.logo) {
1723 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
1725 This->highest_dirty_ps_const = 0;
1726 This->highest_dirty_vs_const = 0;
1730 HeapFree(GetProcessHeap(), 0, This->render_targets);
1731 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1732 HeapFree(GetProcessHeap(), 0, This->swapchains);
1733 This->NumberOfSwapChains = 0;
1734 if(This->palettes) {
1735 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
1736 HeapFree(GetProcessHeap(), 0, This->palettes);
1738 This->NumberOfPalettes = 0;
1740 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1742 if(This->stateBlock) {
1743 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
1744 This->stateBlock = NULL;
1746 if (This->blit_priv) {
1747 This->blitter->free_private(iface);
1749 if (This->fragment_priv) {
1750 This->frag_pipe->free_private(iface);
1752 if (This->shader_priv) {
1753 This->shader_backend->shader_free_private(iface);
1758 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface,
1759 WINED3DPRESENT_PARAMETERS *pPresentationParameters)
1761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1762 IWineD3DSwapChainImpl *swapchain = NULL;
1765 /* Setup the implicit swapchain */
1766 TRACE("Creating implicit swapchain\n");
1767 hr = IWineD3DDeviceParent_CreateSwapChain(This->device_parent,
1768 pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1771 WARN("Failed to create implicit swapchain\n");
1775 This->NumberOfSwapChains = 1;
1776 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1777 if(!This->swapchains) {
1778 ERR("Out of memory!\n");
1781 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1785 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1789 static HRESULT WINAPI device_unload_resource(IWineD3DResource *resource, void *ctx)
1791 IWineD3DResource_UnLoad(resource);
1792 IWineD3DResource_Release(resource);
1796 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface,
1797 D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain)
1799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1800 const struct wined3d_gl_info *gl_info;
1801 struct wined3d_context *context;
1804 TRACE("(%p)\n", This);
1806 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1808 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1809 * it was created. Thus make sure a context is active for the glDelete* calls
1811 context = context_acquire(This, NULL);
1812 gl_info = context->gl_info;
1814 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
1816 /* Unload resources */
1817 IWineD3DDevice_EnumResources(iface, device_unload_resource, NULL);
1819 TRACE("Deleting high order patches\n");
1820 for(i = 0; i < PATCHMAP_SIZE; i++) {
1821 struct list *e1, *e2;
1822 struct WineD3DRectPatch *patch;
1823 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1824 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1825 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1829 /* Delete the mouse cursor texture */
1830 if(This->cursorTexture) {
1832 glDeleteTextures(1, &This->cursorTexture);
1834 This->cursorTexture = 0;
1837 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1838 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1840 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1841 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1844 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1845 * private data, it might contain opengl pointers
1847 if(This->depth_blt_texture) {
1849 glDeleteTextures(1, &This->depth_blt_texture);
1851 This->depth_blt_texture = 0;
1853 if (This->depth_blt_rb) {
1855 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
1857 This->depth_blt_rb = 0;
1858 This->depth_blt_rb_w = 0;
1859 This->depth_blt_rb_h = 0;
1862 /* Release the update stateblock */
1863 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1864 if(This->updateStateBlock != This->stateBlock)
1865 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1867 This->updateStateBlock = NULL;
1869 { /* because were not doing proper internal refcounts releasing the primary state block
1870 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1871 to set this->stateBlock = NULL; first */
1872 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1873 This->stateBlock = NULL;
1875 /* Release the stateblock */
1876 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1877 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1881 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1882 This->blitter->free_private(iface);
1883 This->frag_pipe->free_private(iface);
1884 This->shader_backend->shader_free_private(iface);
1886 /* Release the buffers (with sanity checks)*/
1887 if (This->onscreen_depth_stencil)
1889 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
1890 This->onscreen_depth_stencil = NULL;
1893 TRACE("Releasing the depth stencil buffer at %p\n", This->depth_stencil);
1894 if (This->depth_stencil && IWineD3DSurface_Release((IWineD3DSurface *)This->depth_stencil))
1896 if (This->auto_depth_stencil != This->depth_stencil)
1897 FIXME("(%p) Something is still holding the depth/stencil buffer.\n",This);
1899 This->depth_stencil = NULL;
1901 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1902 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[0]);
1904 TRACE("Setting rendertarget to NULL\n");
1905 This->render_targets[0] = NULL;
1907 if (This->auto_depth_stencil)
1909 if (IWineD3DSurface_Release((IWineD3DSurface *)This->auto_depth_stencil))
1911 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
1913 This->auto_depth_stencil = NULL;
1916 context_release(context);
1918 for(i=0; i < This->NumberOfSwapChains; i++) {
1919 TRACE("Releasing the implicit swapchain %d\n", i);
1920 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1921 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1925 HeapFree(GetProcessHeap(), 0, This->swapchains);
1926 This->swapchains = NULL;
1927 This->NumberOfSwapChains = 0;
1929 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
1930 HeapFree(GetProcessHeap(), 0, This->palettes);
1931 This->palettes = NULL;
1932 This->NumberOfPalettes = 0;
1934 HeapFree(GetProcessHeap(), 0, This->render_targets);
1935 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1936 This->render_targets = NULL;
1937 This->draw_buffers = NULL;
1939 This->d3d_initialized = FALSE;
1944 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1948 for(i=0; i < This->NumberOfSwapChains; i++) {
1949 TRACE("Releasing the implicit swapchain %d\n", i);
1950 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1951 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1955 HeapFree(GetProcessHeap(), 0, This->swapchains);
1956 This->swapchains = NULL;
1957 This->NumberOfSwapChains = 0;
1961 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1962 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1963 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1965 * There is no way to deactivate thread safety once it is enabled.
1967 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1970 /*For now just store the flag(needed in case of ddraw) */
1971 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1974 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
1975 const WINED3DDISPLAYMODE* pMode) {
1977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1978 const struct wined3d_format_desc *format_desc = getFormatDescEntry(pMode->Format, &This->adapter->gl_info);
1982 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1984 /* Resize the screen even without a window:
1985 * The app could have unset it with SetCooperativeLevel, but not called
1986 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1987 * but we don't have any hwnd
1990 memset(&devmode, 0, sizeof(devmode));
1991 devmode.dmSize = sizeof(devmode);
1992 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1993 devmode.dmBitsPerPel = format_desc->byte_count * 8;
1994 devmode.dmPelsWidth = pMode->Width;
1995 devmode.dmPelsHeight = pMode->Height;
1997 devmode.dmDisplayFrequency = pMode->RefreshRate;
1998 if (pMode->RefreshRate != 0) {
1999 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2002 /* Only change the mode if necessary */
2003 if( (This->ddraw_width == pMode->Width) &&
2004 (This->ddraw_height == pMode->Height) &&
2005 (This->ddraw_format == pMode->Format) &&
2006 (pMode->RefreshRate == 0) ) {
2010 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2011 if (ret != DISP_CHANGE_SUCCESSFUL) {
2012 if(devmode.dmDisplayFrequency != 0) {
2013 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2014 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2015 devmode.dmDisplayFrequency = 0;
2016 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2018 if(ret != DISP_CHANGE_SUCCESSFUL) {
2019 return WINED3DERR_NOTAVAILABLE;
2023 /* Store the new values */
2024 This->ddraw_width = pMode->Width;
2025 This->ddraw_height = pMode->Height;
2026 This->ddraw_format = pMode->Format;
2028 /* And finally clip mouse to our screen */
2029 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2030 ClipCursor(&clip_rc);
2035 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2037 *ppD3D = This->wined3d;
2038 TRACE("Returning %p.\n", *ppD3D);
2039 IWineD3D_AddRef(*ppD3D);
2043 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2046 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2047 (This->adapter->TextureRam/(1024*1024)),
2048 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2049 /* return simulated texture memory left */
2050 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2054 * Get / Set Stream Source
2056 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,
2057 IWineD3DBuffer *pStreamData, UINT OffsetInBytes, UINT Stride)
2059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2060 IWineD3DBuffer *oldSrc;
2062 if (StreamNumber >= MAX_STREAMS) {
2063 WARN("Stream out of range %d\n", StreamNumber);
2064 return WINED3DERR_INVALIDCALL;
2065 } else if(OffsetInBytes & 0x3) {
2066 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2067 return WINED3DERR_INVALIDCALL;
2070 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2071 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2073 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2075 if(oldSrc == pStreamData &&
2076 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2077 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2078 TRACE("Application is setting the old values over, nothing to do\n");
2082 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2084 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2085 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2088 /* Handle recording of state blocks */
2089 if (This->isRecordingState) {
2090 TRACE("Recording... not performing anything\n");
2091 if (pStreamData) IWineD3DBuffer_AddRef(pStreamData);
2092 if (oldSrc) IWineD3DBuffer_Release(oldSrc);
2096 if (pStreamData != NULL) {
2097 InterlockedIncrement(&((struct wined3d_buffer *)pStreamData)->bind_count);
2098 IWineD3DBuffer_AddRef(pStreamData);
2100 if (oldSrc != NULL) {
2101 InterlockedDecrement(&((struct wined3d_buffer *)oldSrc)->bind_count);
2102 IWineD3DBuffer_Release(oldSrc);
2105 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2110 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface,
2111 UINT StreamNumber, IWineD3DBuffer **pStream, UINT *pOffset, UINT *pStride)
2113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2115 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2116 This->stateBlock->streamSource[StreamNumber],
2117 This->stateBlock->streamOffset[StreamNumber],
2118 This->stateBlock->streamStride[StreamNumber]);
2120 if (StreamNumber >= MAX_STREAMS) {
2121 WARN("Stream out of range %d\n", StreamNumber);
2122 return WINED3DERR_INVALIDCALL;
2124 *pStream = This->stateBlock->streamSource[StreamNumber];
2125 *pStride = This->stateBlock->streamStride[StreamNumber];
2127 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2130 if (*pStream != NULL) {
2131 IWineD3DBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2136 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2138 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2139 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2141 /* Verify input at least in d3d9 this is invalid*/
2142 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2143 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2144 return WINED3DERR_INVALIDCALL;
2146 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2147 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2148 return WINED3DERR_INVALIDCALL;
2151 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2152 return WINED3DERR_INVALIDCALL;
2155 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2156 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2158 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2159 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2161 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2162 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2163 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2169 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2172 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2173 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2175 TRACE("(%p) : returning %d\n", This, *Divider);
2181 * Get / Set & Multiply Transform
2183 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2186 /* Most of this routine, comments included copied from ddraw tree initially: */
2187 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2189 /* Handle recording of state blocks */
2190 if (This->isRecordingState) {
2191 TRACE("Recording... not performing anything\n");
2192 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2193 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2198 * If the new matrix is the same as the current one,
2199 * we cut off any further processing. this seems to be a reasonable
2200 * optimization because as was noticed, some apps (warcraft3 for example)
2201 * tend towards setting the same matrix repeatedly for some reason.
2203 * From here on we assume that the new matrix is different, wherever it matters.
2205 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2206 TRACE("The app is setting the same matrix over again\n");
2209 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2213 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2214 where ViewMat = Camera space, WorldMat = world space.
2216 In OpenGL, camera and world space is combined into GL_MODELVIEW
2217 matrix. The Projection matrix stay projection matrix.
2220 /* Capture the times we can just ignore the change for now */
2221 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2222 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2223 /* Handled by the state manager */
2226 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2230 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2232 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2233 *pMatrix = This->stateBlock->transforms[State];
2237 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2238 const WINED3DMATRIX *mat = NULL;
2241 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2242 * below means it will be recorded in a state block change, but it
2243 * works regardless where it is recorded.
2244 * If this is found to be wrong, change to StateBlock.
2246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2247 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2249 if (State <= HIGHEST_TRANSFORMSTATE)
2251 mat = &This->updateStateBlock->transforms[State];
2253 FIXME("Unhandled transform state!!\n");
2256 multiply_matrix(&temp, mat, pMatrix);
2258 /* Apply change via set transform - will reapply to eg. lights this way */
2259 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2265 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2266 you can reference any indexes you want as long as that number max are enabled at any
2267 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2268 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2269 but when recording, just build a chain pretty much of commands to be replayed. */
2271 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2273 struct wined3d_light_info *object = NULL;
2274 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2278 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2280 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2284 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2285 return WINED3DERR_INVALIDCALL;
2288 switch(pLight->Type) {
2289 case WINED3DLIGHT_POINT:
2290 case WINED3DLIGHT_SPOT:
2291 case WINED3DLIGHT_PARALLELPOINT:
2292 case WINED3DLIGHT_GLSPOT:
2293 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2296 if (pLight->Attenuation0 < 0.0f || pLight->Attenuation1 < 0.0f || pLight->Attenuation2 < 0.0f)
2298 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2299 return WINED3DERR_INVALIDCALL;
2303 case WINED3DLIGHT_DIRECTIONAL:
2304 /* Ignores attenuation */
2308 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2309 return WINED3DERR_INVALIDCALL;
2312 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2314 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
2315 if(object->OriginalIndex == Index) break;
2320 TRACE("Adding new light\n");
2321 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2323 ERR("Out of memory error when allocating a light\n");
2324 return E_OUTOFMEMORY;
2326 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2327 object->glIndex = -1;
2328 object->OriginalIndex = Index;
2331 /* Initialize the object */
2332 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,
2333 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2334 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2335 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2336 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2337 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2338 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2340 /* Save away the information */
2341 object->OriginalParms = *pLight;
2343 switch (pLight->Type) {
2344 case WINED3DLIGHT_POINT:
2346 object->lightPosn[0] = pLight->Position.x;
2347 object->lightPosn[1] = pLight->Position.y;
2348 object->lightPosn[2] = pLight->Position.z;
2349 object->lightPosn[3] = 1.0f;
2350 object->cutoff = 180.0f;
2354 case WINED3DLIGHT_DIRECTIONAL:
2356 object->lightPosn[0] = -pLight->Direction.x;
2357 object->lightPosn[1] = -pLight->Direction.y;
2358 object->lightPosn[2] = -pLight->Direction.z;
2359 object->lightPosn[3] = 0.0f;
2360 object->exponent = 0.0f;
2361 object->cutoff = 180.0f;
2364 case WINED3DLIGHT_SPOT:
2366 object->lightPosn[0] = pLight->Position.x;
2367 object->lightPosn[1] = pLight->Position.y;
2368 object->lightPosn[2] = pLight->Position.z;
2369 object->lightPosn[3] = 1.0f;
2372 object->lightDirn[0] = pLight->Direction.x;
2373 object->lightDirn[1] = pLight->Direction.y;
2374 object->lightDirn[2] = pLight->Direction.z;
2375 object->lightDirn[3] = 1.0f;
2378 * opengl-ish and d3d-ish spot lights use too different models for the
2379 * light "intensity" as a function of the angle towards the main light direction,
2380 * so we only can approximate very roughly.
2381 * however spot lights are rather rarely used in games (if ever used at all).
2382 * furthermore if still used, probably nobody pays attention to such details.
2384 if (pLight->Falloff == 0) {
2385 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2386 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2387 * will always be 1.0 for both of them, and we don't have to care for the
2388 * rest of the rather complex calculation
2390 object->exponent = 0.0f;
2392 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2393 if (rho < 0.0001f) rho = 0.0001f;
2394 object->exponent = -0.3f/logf(cosf(rho/2));
2396 if (object->exponent > 128.0f)
2398 object->exponent = 128.0f;
2400 object->cutoff = pLight->Phi*90/M_PI;
2406 FIXME("Unrecognized light type %d\n", pLight->Type);
2409 /* Update the live definitions if the light is currently assigned a glIndex */
2410 if (object->glIndex != -1 && !This->isRecordingState) {
2411 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2416 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT *pLight)
2418 struct wined3d_light_info *lightInfo = NULL;
2419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2420 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2422 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2424 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2426 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2427 if(lightInfo->OriginalIndex == Index) break;
2431 if (lightInfo == NULL) {
2432 TRACE("Light information requested but light not defined\n");
2433 return WINED3DERR_INVALIDCALL;
2436 *pLight = lightInfo->OriginalParms;
2441 * Get / Set Light Enable
2442 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2444 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable)
2446 struct wined3d_light_info *lightInfo = NULL;
2447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2448 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2450 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2452 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2454 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2455 if(lightInfo->OriginalIndex == Index) break;
2458 TRACE("Found light: %p\n", lightInfo);
2460 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2461 if (lightInfo == NULL) {
2463 TRACE("Light enabled requested but light not defined, so defining one!\n");
2464 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2466 /* Search for it again! Should be fairly quick as near head of list */
2467 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi])
2469 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2470 if(lightInfo->OriginalIndex == Index) break;
2473 if (lightInfo == NULL) {
2474 FIXME("Adding default lights has failed dismally\n");
2475 return WINED3DERR_INVALIDCALL;
2480 if(lightInfo->glIndex != -1) {
2481 if(!This->isRecordingState) {
2482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2485 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2486 lightInfo->glIndex = -1;
2488 TRACE("Light already disabled, nothing to do\n");
2490 lightInfo->enabled = FALSE;
2492 lightInfo->enabled = TRUE;
2493 if (lightInfo->glIndex != -1) {
2495 TRACE("Nothing to do as light was enabled\n");
2498 /* Find a free gl light */
2499 for(i = 0; i < This->maxConcurrentLights; i++) {
2500 if(This->updateStateBlock->activeLights[i] == NULL) {
2501 This->updateStateBlock->activeLights[i] = lightInfo;
2502 lightInfo->glIndex = i;
2506 if(lightInfo->glIndex == -1) {
2507 /* Our tests show that Windows returns D3D_OK in this situation, even with
2508 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2509 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2510 * as well for those lights.
2512 * TODO: Test how this affects rendering
2514 WARN("Too many concurrently active lights\n");
2518 /* i == lightInfo->glIndex */
2519 if(!This->isRecordingState) {
2520 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2528 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable)
2530 struct wined3d_light_info *lightInfo = NULL;
2531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2533 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2534 TRACE("(%p) : for idx(%d)\n", This, Index);
2536 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi])
2538 lightInfo = LIST_ENTRY(e, struct wined3d_light_info, entry);
2539 if(lightInfo->OriginalIndex == Index) break;
2543 if (lightInfo == NULL) {
2544 TRACE("Light enabled state requested but light not defined\n");
2545 return WINED3DERR_INVALIDCALL;
2547 /* true is 128 according to SetLightEnable */
2548 *pEnable = lightInfo->enabled ? 128 : 0;
2553 * Get / Set Clip Planes
2555 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2557 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2559 /* Validate Index */
2560 if (Index >= This->adapter->gl_info.limits.clipplanes)
2562 TRACE("Application has requested clipplane this device doesn't support\n");
2563 return WINED3DERR_INVALIDCALL;
2566 This->updateStateBlock->changed.clipplane |= 1 << Index;
2568 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2569 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2570 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2571 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2572 TRACE("Application is setting old values over, nothing to do\n");
2576 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2577 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2578 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2579 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2581 /* Handle recording of state blocks */
2582 if (This->isRecordingState) {
2583 TRACE("Recording... not performing anything\n");
2587 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2592 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2594 TRACE("(%p) : for idx %d\n", This, Index);
2596 /* Validate Index */
2597 if (Index >= This->adapter->gl_info.limits.clipplanes)
2599 TRACE("Application has requested clipplane this device doesn't support\n");
2600 return WINED3DERR_INVALIDCALL;
2603 pPlane[0] = This->stateBlock->clipplane[Index][0];
2604 pPlane[1] = This->stateBlock->clipplane[Index][1];
2605 pPlane[2] = This->stateBlock->clipplane[Index][2];
2606 pPlane[3] = This->stateBlock->clipplane[Index][3];
2611 * Get / Set Clip Plane Status
2612 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2614 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2616 FIXME("(%p) : stub\n", This);
2617 if (NULL == pClipStatus) {
2618 return WINED3DERR_INVALIDCALL;
2620 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2621 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2625 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2627 FIXME("(%p) : stub\n", This);
2628 if (NULL == pClipStatus) {
2629 return WINED3DERR_INVALIDCALL;
2631 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2632 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2637 * Get / Set Material
2639 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2642 This->updateStateBlock->changed.material = TRUE;
2643 This->updateStateBlock->material = *pMaterial;
2645 /* Handle recording of state blocks */
2646 if (This->isRecordingState) {
2647 TRACE("Recording... not performing anything\n");
2651 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2655 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2657 *pMaterial = This->updateStateBlock->material;
2658 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2659 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2660 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2661 pMaterial->Ambient.b, pMaterial->Ambient.a);
2662 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2663 pMaterial->Specular.b, pMaterial->Specular.a);
2664 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2665 pMaterial->Emissive.b, pMaterial->Emissive.a);
2666 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2674 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndexBuffer(IWineD3DDevice *iface,
2675 IWineD3DBuffer *pIndexData, WINED3DFORMAT fmt)
2677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2678 IWineD3DBuffer *oldIdxs;
2680 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2681 oldIdxs = This->updateStateBlock->pIndexData;
2683 This->updateStateBlock->changed.indices = TRUE;
2684 This->updateStateBlock->pIndexData = pIndexData;
2685 This->updateStateBlock->IndexFmt = fmt;
2687 /* Handle recording of state blocks */
2688 if (This->isRecordingState) {
2689 TRACE("Recording... not performing anything\n");
2690 if(pIndexData) IWineD3DBuffer_AddRef(pIndexData);
2691 if(oldIdxs) IWineD3DBuffer_Release(oldIdxs);
2695 if(oldIdxs != pIndexData) {
2696 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2698 InterlockedIncrement(&((struct wined3d_buffer *)pIndexData)->bind_count);
2699 IWineD3DBuffer_AddRef(pIndexData);
2702 InterlockedDecrement(&((struct wined3d_buffer *)oldIdxs)->bind_count);
2703 IWineD3DBuffer_Release(oldIdxs);
2710 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndexBuffer(IWineD3DDevice *iface, IWineD3DBuffer **ppIndexData)
2712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2714 *ppIndexData = This->stateBlock->pIndexData;
2716 /* up ref count on ppindexdata */
2718 IWineD3DBuffer_AddRef(*ppIndexData);
2719 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2721 TRACE("(%p) No index data set\n", This);
2723 TRACE("Returning %p\n", *ppIndexData);
2728 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2729 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2731 TRACE("(%p)->(%d)\n", This, BaseIndex);
2733 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2734 TRACE("Application is setting the old value over, nothing to do\n");
2738 This->updateStateBlock->baseVertexIndex = BaseIndex;
2740 if (This->isRecordingState) {
2741 TRACE("Recording... not performing anything\n");
2744 /* The base vertex index affects the stream sources */
2745 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2749 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2751 TRACE("(%p) : base_index %p\n", This, base_index);
2753 *base_index = This->stateBlock->baseVertexIndex;
2755 TRACE("Returning %u\n", *base_index);
2761 * Get / Set Viewports
2763 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2766 TRACE("(%p)\n", This);
2767 This->updateStateBlock->changed.viewport = TRUE;
2768 This->updateStateBlock->viewport = *pViewport;
2770 /* Handle recording of state blocks */
2771 if (This->isRecordingState) {
2772 TRACE("Recording... not performing anything\n");
2776 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2777 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2779 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2784 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2786 TRACE("(%p)\n", This);
2787 *pViewport = This->stateBlock->viewport;
2792 * Get / Set Render States
2793 * TODO: Verify against dx9 definitions
2795 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2798 DWORD oldValue = This->stateBlock->renderState[State];
2800 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2802 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
2803 This->updateStateBlock->renderState[State] = Value;
2805 /* Handle recording of state blocks */
2806 if (This->isRecordingState) {
2807 TRACE("Recording... not performing anything\n");
2811 /* Compared here and not before the assignment to allow proper stateblock recording */
2812 if(Value == oldValue) {
2813 TRACE("Application is setting the old value over, nothing to do\n");
2815 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2821 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2823 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2824 *pValue = This->stateBlock->renderState[State];
2829 * Get / Set Sampler States
2830 * TODO: Verify against dx9 definitions
2833 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2837 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2838 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2840 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2841 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2844 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2845 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2846 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2849 * SetSampler is designed to allow for more than the standard up to 8 textures
2850 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2851 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2853 * http://developer.nvidia.com/object/General_FAQ.html#t6
2855 * There are two new settings for GForce
2857 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2858 * and the texture one:
2859 * GL_MAX_TEXTURE_COORDS_ARB.
2860 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2863 oldValue = This->stateBlock->samplerState[Sampler][Type];
2864 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2865 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
2867 /* Handle recording of state blocks */
2868 if (This->isRecordingState) {
2869 TRACE("Recording... not performing anything\n");
2873 if(oldValue == Value) {
2874 TRACE("Application is setting the old value over, nothing to do\n");
2878 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2883 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2886 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2887 This, Sampler, debug_d3dsamplerstate(Type), Type);
2889 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2890 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2893 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
2894 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
2895 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
2897 *Value = This->stateBlock->samplerState[Sampler][Type];
2898 TRACE("(%p) : Returning %#x\n", This, *Value);
2903 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2906 This->updateStateBlock->changed.scissorRect = TRUE;
2907 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2908 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2911 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2913 if(This->isRecordingState) {
2914 TRACE("Recording... not performing anything\n");
2918 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2923 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2926 *pRect = This->updateStateBlock->scissorRect;
2927 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2931 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2933 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2935 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2937 if (pDecl) IWineD3DVertexDeclaration_AddRef(pDecl);
2938 if (oldDecl) IWineD3DVertexDeclaration_Release(oldDecl);
2940 This->updateStateBlock->vertexDecl = pDecl;
2941 This->updateStateBlock->changed.vertexDecl = TRUE;
2943 if (This->isRecordingState) {
2944 TRACE("Recording... not performing anything\n");
2946 } else if(pDecl == oldDecl) {
2947 /* Checked after the assignment to allow proper stateblock recording */
2948 TRACE("Application is setting the old declaration over, nothing to do\n");
2952 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2956 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2959 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2961 *ppDecl = This->stateBlock->vertexDecl;
2962 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2966 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2968 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2970 This->updateStateBlock->vertexShader = pShader;
2971 This->updateStateBlock->changed.vertexShader = TRUE;
2973 if (This->isRecordingState) {
2974 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2975 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2976 TRACE("Recording... not performing anything\n");
2978 } else if(oldShader == pShader) {
2979 /* Checked here to allow proper stateblock recording */
2980 TRACE("App is setting the old shader over, nothing to do\n");
2984 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2985 if(pShader) IWineD3DVertexShader_AddRef(pShader);
2986 if(oldShader) IWineD3DVertexShader_Release(oldShader);
2988 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2993 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2996 if (NULL == ppShader) {
2997 return WINED3DERR_INVALIDCALL;
2999 *ppShader = This->stateBlock->vertexShader;
3000 if( NULL != *ppShader)
3001 IWineD3DVertexShader_AddRef(*ppShader);
3003 TRACE("(%p) : returning %p\n", This, *ppShader);
3007 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3008 IWineD3DDevice *iface,
3010 CONST BOOL *srcData,
3013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3014 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3016 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3017 iface, srcData, start, count);
3019 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3021 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3022 for (i = 0; i < cnt; i++)
3023 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3025 for (i = start; i < cnt + start; ++i) {
3026 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3029 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3034 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3035 IWineD3DDevice *iface,
3040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3041 int cnt = min(count, MAX_CONST_B - start);
3043 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3044 iface, dstData, start, count);
3046 if (dstData == NULL || cnt < 0)
3047 return WINED3DERR_INVALIDCALL;
3049 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3053 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3054 IWineD3DDevice *iface,
3059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3060 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3062 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3063 iface, srcData, start, count);
3065 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3067 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3068 for (i = 0; i < cnt; i++)
3069 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3070 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3072 for (i = start; i < cnt + start; ++i) {
3073 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3076 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3081 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3082 IWineD3DDevice *iface,
3087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3088 int cnt = min(count, MAX_CONST_I - start);
3090 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3091 iface, dstData, start, count);
3093 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= 0)
3094 return WINED3DERR_INVALIDCALL;
3096 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3100 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3101 IWineD3DDevice *iface,
3103 CONST float *srcData,
3106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3109 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3110 iface, srcData, start, count);
3112 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3113 if (srcData == NULL || start + count > This->d3d_vshader_constantF || start > This->d3d_vshader_constantF)
3114 return WINED3DERR_INVALIDCALL;
3116 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3118 for (i = 0; i < count; i++)
3119 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3120 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3123 if (!This->isRecordingState)
3125 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3126 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3129 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3130 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3135 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3136 IWineD3DDevice *iface,
3141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3142 int cnt = min(count, This->d3d_vshader_constantF - start);
3144 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3145 iface, dstData, start, count);
3147 if (dstData == NULL || cnt < 0)
3148 return WINED3DERR_INVALIDCALL;
3150 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3154 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3156 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3158 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3162 static void device_map_stage(IWineD3DDeviceImpl *This, DWORD stage, DWORD unit)
3164 DWORD i = This->rev_tex_unit_map[unit];
3165 DWORD j = This->texUnitMap[stage];
3167 This->texUnitMap[stage] = unit;
3168 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
3170 This->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
3173 This->rev_tex_unit_map[unit] = stage;
3174 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
3176 This->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
3180 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3183 This->fixed_function_usage_map = 0;
3184 for (i = 0; i < MAX_TEXTURES; ++i) {
3185 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3186 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3187 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3188 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3189 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3190 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3191 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3192 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3194 if (color_op == WINED3DTOP_DISABLE) {
3195 /* Not used, and disable higher stages */
3199 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3200 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3201 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3202 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3203 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3204 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3205 This->fixed_function_usage_map |= (1 << i);
3208 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3209 This->fixed_function_usage_map |= (1 << (i + 1));
3214 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3216 unsigned int i, tex;
3219 device_update_fixed_function_usage_map(This);
3220 ffu_map = This->fixed_function_usage_map;
3222 if (This->max_ffp_textures == gl_info->limits.texture_stages
3223 || This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures)
3225 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3227 if (!(ffu_map & 1)) continue;
3229 if (This->texUnitMap[i] != i) {
3230 device_map_stage(This, i, i);
3231 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3232 markTextureStagesDirty(This, i);
3238 /* Now work out the mapping */
3240 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3242 if (!(ffu_map & 1)) continue;
3244 if (This->texUnitMap[i] != tex) {
3245 device_map_stage(This, i, tex);
3246 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3247 markTextureStagesDirty(This, i);
3254 static void device_map_psamplers(IWineD3DDeviceImpl *This, const struct wined3d_gl_info *gl_info)
3256 const WINED3DSAMPLER_TEXTURE_TYPE *sampler_type =
3257 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.sampler_type;
3260 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3261 if (sampler_type[i] && This->texUnitMap[i] != i)
3263 device_map_stage(This, i, i);
3264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3265 if (i < gl_info->limits.texture_stages)
3267 markTextureStagesDirty(This, i);
3273 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3274 const DWORD *vshader_sampler_tokens, DWORD unit)
3276 DWORD current_mapping = This->rev_tex_unit_map[unit];
3278 /* Not currently used */
3279 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
3281 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3282 /* Used by a fragment sampler */
3284 if (!pshader_sampler_tokens) {
3285 /* No pixel shader, check fixed function */
3286 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3289 /* Pixel shader, check the shader's sampler map */
3290 return !pshader_sampler_tokens[current_mapping];
3293 /* Used by a vertex sampler */
3294 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
3297 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps, const struct wined3d_gl_info *gl_info)
3299 const WINED3DSAMPLER_TEXTURE_TYPE *vshader_sampler_type =
3300 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.sampler_type;
3301 const WINED3DSAMPLER_TEXTURE_TYPE *pshader_sampler_type = NULL;
3302 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
3306 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3308 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3309 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3310 pshader_sampler_type = pshader->baseShader.reg_maps.sampler_type;
3313 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3314 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3315 if (vshader_sampler_type[i])
3317 if (This->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
3319 /* Already mapped somewhere */
3323 while (start >= 0) {
3324 if (device_unit_free_for_vs(This, pshader_sampler_type, vshader_sampler_type, start))
3326 device_map_stage(This, vsampler_idx, start);
3327 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3339 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This)
3341 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3342 BOOL vs = use_vs(This->stateBlock);
3343 BOOL ps = use_ps(This->stateBlock);
3346 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3347 * that would be really messy and require shader recompilation
3348 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3349 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3351 if (ps) device_map_psamplers(This, gl_info);
3352 else device_map_fixed_function_samplers(This, gl_info);
3354 if (vs) device_map_vsamplers(This, ps, gl_info);
3357 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3359 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3360 This->updateStateBlock->pixelShader = pShader;
3361 This->updateStateBlock->changed.pixelShader = TRUE;
3363 /* Handle recording of state blocks */
3364 if (This->isRecordingState) {
3365 TRACE("Recording... not performing anything\n");
3368 if (This->isRecordingState) {
3369 TRACE("Recording... not performing anything\n");
3370 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3371 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3375 if(pShader == oldShader) {
3376 TRACE("App is setting the old pixel shader over, nothing to do\n");
3380 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3381 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3383 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3384 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3389 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3392 if (NULL == ppShader) {
3393 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3394 return WINED3DERR_INVALIDCALL;
3397 *ppShader = This->stateBlock->pixelShader;
3398 if (NULL != *ppShader) {
3399 IWineD3DPixelShader_AddRef(*ppShader);
3401 TRACE("(%p) : returning %p\n", This, *ppShader);
3405 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3406 IWineD3DDevice *iface,
3408 CONST BOOL *srcData,
3411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3412 unsigned int i, cnt = min(count, MAX_CONST_B - start);
3414 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3415 iface, srcData, start, count);
3417 if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
3419 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3420 for (i = 0; i < cnt; i++)
3421 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3423 for (i = start; i < cnt + start; ++i) {
3424 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3427 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3432 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3433 IWineD3DDevice *iface,
3438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3439 int cnt = min(count, MAX_CONST_B - start);
3441 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3442 iface, dstData, start, count);
3444 if (dstData == NULL || cnt < 0)
3445 return WINED3DERR_INVALIDCALL;
3447 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3451 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3452 IWineD3DDevice *iface,
3457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3458 unsigned int i, cnt = min(count, MAX_CONST_I - start);
3460 TRACE("(iface %p, srcData %p, start %u, count %u)\n",
3461 iface, srcData, start, count);
3463 if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
3465 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3466 for (i = 0; i < cnt; i++)
3467 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3468 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3470 for (i = start; i < cnt + start; ++i) {
3471 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3474 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3479 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3480 IWineD3DDevice *iface,
3485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3486 int cnt = min(count, MAX_CONST_I - start);
3488 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3489 iface, dstData, start, count);
3491 if (dstData == NULL || cnt < 0)
3492 return WINED3DERR_INVALIDCALL;
3494 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3498 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3499 IWineD3DDevice *iface,
3501 CONST float *srcData,
3504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3507 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3508 iface, srcData, start, count);
3510 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3511 if (srcData == NULL || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
3512 return WINED3DERR_INVALIDCALL;
3514 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3516 for (i = 0; i < count; i++)
3517 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3518 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3521 if (!This->isRecordingState)
3523 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3524 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3527 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3528 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3533 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3534 IWineD3DDevice *iface,
3539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3540 int cnt = min(count, This->d3d_pshader_constantF - start);
3542 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3543 iface, dstData, start, count);
3545 if (dstData == NULL || cnt < 0)
3546 return WINED3DERR_INVALIDCALL;
3548 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3552 /* Context activation is done by the caller. */
3553 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3554 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
3555 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD dwFlags,
3558 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3559 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3562 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3566 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3568 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3571 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3573 ERR("Source has no position mask\n");
3574 return WINED3DERR_INVALIDCALL;
3577 /* We might access VBOs from this code, so hold the lock */
3580 if (!dest->resource.allocatedMemory)
3581 buffer_get_sysmem(dest, gl_info);
3583 /* Get a pointer into the destination vbo(create one if none exists) and
3584 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3586 if (!dest->buffer_object && gl_info->supported[ARB_VERTEX_BUFFER_OBJECT])
3588 dest->flags |= WINED3D_BUFFER_CREATEBO;
3589 IWineD3DBuffer_PreLoad((IWineD3DBuffer *)dest);
3592 if (dest->buffer_object)
3594 unsigned char extrabytes = 0;
3595 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3596 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3597 * this may write 4 extra bytes beyond the area that should be written
3599 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3600 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3601 if(!dest_conv_addr) {
3602 ERR("Out of memory\n");
3603 /* Continue without storing converted vertices */
3605 dest_conv = dest_conv_addr;
3609 * a) WINED3DRS_CLIPPING is enabled
3610 * b) WINED3DVOP_CLIP is passed
3612 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3613 static BOOL warned = FALSE;
3615 * The clipping code is not quite correct. Some things need
3616 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3617 * so disable clipping for now.
3618 * (The graphics in Half-Life are broken, and my processvertices
3619 * test crashes with IDirect3DDevice3)
3625 FIXME("Clipping is broken and disabled for now\n");
3627 } else doClip = FALSE;
3628 dest_ptr = ((char *)buffer_get_sysmem(dest, gl_info)) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3630 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3633 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3634 WINED3DTS_PROJECTION,
3636 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3637 WINED3DTS_WORLDMATRIX(0),
3640 TRACE("View mat:\n");
3641 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);
3642 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);
3643 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);
3644 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);
3646 TRACE("Proj mat:\n");
3647 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);
3648 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);
3649 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);
3650 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);
3652 TRACE("World mat:\n");
3653 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);
3654 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);
3655 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);
3656 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);
3658 /* Get the viewport */
3659 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3660 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3661 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3663 multiply_matrix(&mat,&view_mat,&world_mat);
3664 multiply_matrix(&mat,&proj_mat,&mat);
3666 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3668 for (i = 0; i < dwCount; i+= 1) {
3669 unsigned int tex_index;
3671 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3672 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3673 /* The position first */
3674 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3675 const float *p = (const float *)(element->data + i * element->stride);
3677 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3679 /* Multiplication with world, view and projection matrix */
3680 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);
3681 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);
3682 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);
3683 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);
3685 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3687 /* WARNING: The following things are taken from d3d7 and were not yet checked
3688 * against d3d8 or d3d9!
3691 /* Clipping conditions: From msdn
3693 * A vertex is clipped if it does not match the following requirements
3697 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3699 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3700 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3705 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3706 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3709 /* "Normal" viewport transformation (not clipped)
3710 * 1) The values are divided by rhw
3711 * 2) The y axis is negative, so multiply it with -1
3712 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3713 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3714 * 4) Multiply x with Width/2 and add Width/2
3715 * 5) The same for the height
3716 * 6) Add the viewpoint X and Y to the 2D coordinates and
3717 * The minimum Z value to z
3718 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3720 * Well, basically it's simply a linear transformation into viewport
3732 z *= vp.MaxZ - vp.MinZ;
3734 x += vp.Width / 2 + vp.X;
3735 y += vp.Height / 2 + vp.Y;
3740 /* That vertex got clipped
3741 * Contrary to OpenGL it is not dropped completely, it just
3742 * undergoes a different calculation.
3744 TRACE("Vertex got clipped\n");
3751 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3752 * outside of the main vertex buffer memory. That needs some more
3757 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3760 ( (float *) dest_ptr)[0] = x;
3761 ( (float *) dest_ptr)[1] = y;
3762 ( (float *) dest_ptr)[2] = z;
3763 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3765 dest_ptr += 3 * sizeof(float);
3767 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3768 dest_ptr += sizeof(float);
3773 ( (float *) dest_conv)[0] = x * w;
3774 ( (float *) dest_conv)[1] = y * w;
3775 ( (float *) dest_conv)[2] = z * w;
3776 ( (float *) dest_conv)[3] = w;
3778 dest_conv += 3 * sizeof(float);
3780 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3781 dest_conv += sizeof(float);
3785 if (DestFVF & WINED3DFVF_PSIZE) {
3786 dest_ptr += sizeof(DWORD);
3787 if(dest_conv) dest_conv += sizeof(DWORD);
3789 if (DestFVF & WINED3DFVF_NORMAL) {
3790 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3791 const float *normal = (const float *)(element->data + i * element->stride);
3792 /* AFAIK this should go into the lighting information */
3793 FIXME("Didn't expect the destination to have a normal\n");
3794 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3796 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3800 if (DestFVF & WINED3DFVF_DIFFUSE) {
3801 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3802 const DWORD *color_d = (const DWORD *)(element->data + i * element->stride);
3803 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3805 static BOOL warned = FALSE;
3808 ERR("No diffuse color in source, but destination has one\n");
3812 *( (DWORD *) dest_ptr) = 0xffffffff;
3813 dest_ptr += sizeof(DWORD);
3816 *( (DWORD *) dest_conv) = 0xffffffff;
3817 dest_conv += sizeof(DWORD);
3821 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3823 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3824 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3825 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3826 dest_conv += sizeof(DWORD);
3831 if (DestFVF & WINED3DFVF_SPECULAR)
3833 /* What's the color value in the feedback buffer? */
3834 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3835 const DWORD *color_s = (const DWORD *)(element->data + i * element->stride);
3836 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3838 static BOOL warned = FALSE;
3841 ERR("No specular color in source, but destination has one\n");
3845 *( (DWORD *) dest_ptr) = 0xFF000000;
3846 dest_ptr += sizeof(DWORD);
3849 *( (DWORD *) dest_conv) = 0xFF000000;
3850 dest_conv += sizeof(DWORD);
3854 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3856 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3857 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3858 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3859 dest_conv += sizeof(DWORD);
3864 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3865 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3866 const float *tex_coord = (const float *)(element->data + i * element->stride);
3867 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3869 ERR("No source texture, but destination requests one\n");
3870 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3871 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3874 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3876 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3883 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->buffer_object));
3884 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3885 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3886 dwCount * get_flexible_vertex_size(DestFVF),
3888 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3889 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3896 #undef copy_and_next
3898 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex,
3899 UINT VertexCount, IWineD3DBuffer *pDestBuffer, IWineD3DVertexDeclaration *pVertexDecl, DWORD Flags,
3902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3903 struct wined3d_stream_info stream_info;
3904 const struct wined3d_gl_info *gl_info;
3905 struct wined3d_context *context;
3906 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3909 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3912 ERR("Output vertex declaration not implemented yet\n");
3915 /* Need any context to write to the vbo. */
3916 context = context_acquire(This, NULL);
3917 gl_info = context->gl_info;
3919 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3920 * control the streamIsUP flag, thus restore it afterwards.
3922 This->stateBlock->streamIsUP = FALSE;
3923 device_stream_info_from_declaration(This, FALSE, &stream_info, &vbo);
3924 This->stateBlock->streamIsUP = streamWasUP;
3926 if(vbo || SrcStartIndex) {
3928 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
3929 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the stream_info structure
3931 * Also get the start index in, but only loop over all elements if there's something to add at all.
3933 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3935 struct wined3d_stream_info_element *e;
3937 if (!(stream_info.use_map & (1 << i))) continue;
3939 e = &stream_info.elements[i];
3940 if (e->buffer_object)
3942 struct wined3d_buffer *vb = (struct wined3d_buffer *)This->stateBlock->streamSource[e->stream_idx];
3943 e->buffer_object = 0;
3944 e->data = (BYTE *)((ULONG_PTR)e->data + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
3946 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3947 vb->buffer_object = 0;
3950 if (e->data) e->data += e->stride * SrcStartIndex;
3954 hr = process_vertices_strided(This, DestIndex, VertexCount, &stream_info,
3955 (struct wined3d_buffer *)pDestBuffer, Flags, DestFVF);
3957 context_release(context);
3963 * Get / Set Texture Stage States
3964 * TODO: Verify against dx9 definitions
3966 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3968 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3969 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
3971 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3973 if (Stage >= gl_info->limits.texture_stages)
3975 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3976 Stage, gl_info->limits.texture_stages - 1);
3980 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
3981 This->updateStateBlock->textureState[Stage][Type] = Value;
3983 if (This->isRecordingState) {
3984 TRACE("Recording... not performing anything\n");
3988 /* Checked after the assignments to allow proper stateblock recording */
3989 if(oldValue == Value) {
3990 TRACE("App is setting the old value over, nothing to do\n");
3994 if(Stage > This->stateBlock->lowest_disabled_stage &&
3995 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3996 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3997 * Changes in other states are important on disabled stages too
4002 if(Type == WINED3DTSS_COLOROP) {
4005 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4006 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4007 * they have to be disabled
4009 * The current stage is dirtified below.
4011 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4012 TRACE("Additionally dirtifying stage %u\n", i);
4013 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4015 This->stateBlock->lowest_disabled_stage = Stage;
4016 TRACE("New lowest disabled: %u\n", Stage);
4017 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4018 /* Previously disabled stage enabled. Stages above it may need enabling
4019 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4020 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4022 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4025 for (i = Stage + 1; i < This->adapter->gl_info.limits.texture_stages; ++i)
4027 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4030 TRACE("Additionally dirtifying stage %u due to enable\n", i);
4031 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4033 This->stateBlock->lowest_disabled_stage = i;
4034 TRACE("New lowest disabled: %u\n", i);
4038 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4043 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4045 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4046 *pValue = This->updateStateBlock->textureState[Stage][Type];
4053 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface,
4054 DWORD stage, IWineD3DBaseTexture *texture)
4056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4057 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
4058 IWineD3DBaseTexture *prev;
4060 TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4062 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
4063 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4065 /* Windows accepts overflowing this array... we do not. */
4066 if (stage >= sizeof(This->stateBlock->textures) / sizeof(*This->stateBlock->textures))
4068 WARN("Ignoring invalid stage %u.\n", stage);
4072 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4073 if (texture && ((IWineD3DTextureImpl *)texture)->resource.pool == WINED3DPOOL_SCRATCH)
4075 WARN("Rejecting attempt to set scratch texture.\n");
4076 return WINED3DERR_INVALIDCALL;
4079 This->updateStateBlock->changed.textures |= 1 << stage;
4081 prev = This->updateStateBlock->textures[stage];
4082 TRACE("Previous texture %p.\n", prev);
4084 if (texture == prev)
4086 TRACE("App is setting the same texture again, nothing to do.\n");
4090 TRACE("Setting new texture to %p.\n", texture);
4091 This->updateStateBlock->textures[stage] = texture;
4093 if (This->isRecordingState)
4095 TRACE("Recording... not performing anything\n");
4097 if (texture) IWineD3DBaseTexture_AddRef(texture);
4098 if (prev) IWineD3DBaseTexture_Release(prev);
4105 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)texture;
4106 LONG bind_count = InterlockedIncrement(&t->baseTexture.bindCount);
4107 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(texture);
4109 IWineD3DBaseTexture_AddRef(texture);
4111 if (!prev || dimensions != IWineD3DBaseTexture_GetTextureDimensions(prev))
4113 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4116 if (!prev && stage < gl_info->limits.texture_stages)
4118 /* The source arguments for color and alpha ops have different
4119 * meanings when a NULL texture is bound, so the COLOROP and
4120 * ALPHAOP have to be dirtified. */
4121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4125 if (bind_count == 1) t->baseTexture.sampler = stage;
4130 IWineD3DBaseTextureImpl *t = (IWineD3DBaseTextureImpl *)prev;
4131 LONG bind_count = InterlockedDecrement(&t->baseTexture.bindCount);
4133 IWineD3DBaseTexture_Release(prev);
4135 if (!texture && stage < gl_info->limits.texture_stages)
4137 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_COLOROP));
4138 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, WINED3DTSS_ALPHAOP));
4141 if (bind_count && t->baseTexture.sampler == stage)
4145 /* Search for other stages the texture is bound to. Shouldn't
4146 * happen if applications bind textures to a single stage only. */
4147 TRACE("Searching for other stages the texture is bound to.\n");
4148 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4150 if (This->updateStateBlock->textures[i] == prev)
4152 TRACE("Texture is also bound to stage %u.\n", i);
4153 t->baseTexture.sampler = i;
4160 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(stage));
4165 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4168 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4170 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4171 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4174 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4175 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4176 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4179 *ppTexture=This->stateBlock->textures[Stage];
4181 IWineD3DBaseTexture_AddRef(*ppTexture);
4183 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4191 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT swapchain_idx,
4192 UINT backbuffer_idx, WINED3DBACKBUFFER_TYPE backbuffer_type, IWineD3DSurface **backbuffer)
4194 IWineD3DSwapChain *swapchain;
4197 TRACE("iface %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
4198 iface, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
4200 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
4203 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
4207 hr = IWineD3DSwapChain_GetBackBuffer(swapchain, backbuffer_idx, backbuffer_type, backbuffer);
4208 IWineD3DSwapChain_Release(swapchain);
4211 WARN("Failed to get backbuffer %u, hr %#x.\n", backbuffer_idx, hr);
4218 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4220 WARN("(%p) : stub, calling idirect3d for now\n", This);
4221 return IWineD3D_GetDeviceCaps(This->wined3d, This->adapter->ordinal, This->devType, pCaps);
4224 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4226 IWineD3DSwapChain *swapChain;
4229 if(iSwapChain > 0) {
4230 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4231 if (hr == WINED3D_OK) {
4232 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4233 IWineD3DSwapChain_Release(swapChain);
4235 FIXME("(%p) Error getting display mode\n", This);
4238 /* Don't read the real display mode,
4239 but return the stored mode instead. X11 can't change the color
4240 depth, and some apps are pretty angry if they SetDisplayMode from
4241 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4243 Also don't relay to the swapchain because with ddraw it's possible
4244 that there isn't a swapchain at all */
4245 pMode->Width = This->ddraw_width;
4246 pMode->Height = This->ddraw_height;
4247 pMode->Format = This->ddraw_format;
4248 pMode->RefreshRate = 0;
4256 * Stateblock related functions
4259 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4261 IWineD3DStateBlock *stateblock;
4264 TRACE("(%p)\n", This);
4266 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4268 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4269 if (FAILED(hr)) return hr;
4271 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4272 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4273 This->isRecordingState = TRUE;
4275 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4280 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4282 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4284 if (!This->isRecordingState) {
4285 WARN("(%p) not recording! returning error\n", This);
4286 *ppStateBlock = NULL;
4287 return WINED3DERR_INVALIDCALL;
4290 stateblock_init_contained_states(object);
4292 *ppStateBlock = (IWineD3DStateBlock*) object;
4293 This->isRecordingState = FALSE;
4294 This->updateStateBlock = This->stateBlock;
4295 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4296 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4297 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4302 * Scene related functions
4304 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4305 /* At the moment we have no need for any functionality at the beginning
4307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4308 TRACE("(%p)\n", This);
4311 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4312 return WINED3DERR_INVALIDCALL;
4314 This->inScene = TRUE;
4318 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface)
4320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4321 struct wined3d_context *context;
4323 TRACE("(%p)\n", This);
4325 if(!This->inScene) {
4326 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4327 return WINED3DERR_INVALIDCALL;
4330 context = context_acquire(This, NULL);
4331 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4333 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4335 context_release(context);
4337 This->inScene = FALSE;
4341 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4342 const RECT *pSourceRect, const RECT *pDestRect,
4343 HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
4345 IWineD3DSwapChain *swapChain = NULL;
4347 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4349 TRACE("iface %p.\n", iface);
4351 for(i = 0 ; i < swapchains ; i ++) {
4353 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4354 TRACE("presentinng chain %d, %p\n", i, swapChain);
4355 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4356 IWineD3DSwapChain_Release(swapChain);
4362 static BOOL is_full_clear(IWineD3DSurfaceImpl *target, const RECT *draw_rect, const RECT *clear_rect)
4364 /* partial draw rect */
4365 if (draw_rect->left || draw_rect->top
4366 || draw_rect->right < target->currentDesc.Width
4367 || draw_rect->bottom < target->currentDesc.Height)
4370 /* partial clear rect */
4371 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
4372 || clear_rect->right < target->currentDesc.Width
4373 || clear_rect->bottom < target->currentDesc.Height))
4379 static void prepare_ds_clear(IWineD3DSurfaceImpl *ds, struct wined3d_context *context,
4380 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect)
4382 RECT current_rect, r;
4384 if (ds->Flags & location)
4385 SetRect(¤t_rect, 0, 0,
4386 ds->ds_current_size.cx,
4387 ds->ds_current_size.cy);
4389 SetRectEmpty(¤t_rect);
4391 IntersectRect(&r, draw_rect, ¤t_rect);
4392 if (EqualRect(&r, draw_rect))
4394 /* current_rect ⊇ draw_rect, modify only. */
4395 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
4399 if (EqualRect(&r, ¤t_rect))
4401 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
4405 /* Full clear, modify only. */
4406 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
4410 IntersectRect(&r, draw_rect, clear_rect);
4411 if (EqualRect(&r, draw_rect))
4413 /* clear_rect ⊇ draw_rect, modify only. */
4414 surface_modify_ds_location(ds, location, draw_rect->right, draw_rect->bottom);
4420 surface_load_ds_location(ds, context, location);
4421 surface_modify_ds_location(ds, location, ds->ds_current_size.cx, ds->ds_current_size.cy);
4424 /* Not called from the VTable (internal subroutine) */
4425 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4426 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4428 const RECT *clear_rect = (Count > 0 && pRects) ? (const RECT *)pRects : NULL;
4429 IWineD3DSurfaceImpl *depth_stencil = This->depth_stencil;
4430 GLbitfield glMask = 0;
4432 UINT drawable_width, drawable_height;
4433 struct wined3d_context *context;
4436 device_get_draw_rect(This, &draw_rect);
4438 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4439 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4440 * for the cleared parts, and the untouched parts.
4442 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4443 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4444 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4445 * checking all this if the dest surface is in the drawable anyway.
4447 if (Flags & WINED3DCLEAR_TARGET && !(target->Flags & SFLAG_INDRAWABLE))
4449 if (!is_full_clear(target, &draw_rect, clear_rect))
4450 IWineD3DSurface_LoadLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, NULL);
4453 context = context_acquire(This, target);
4454 if (!context->valid)
4456 context_release(context);
4457 WARN("Invalid context, skipping clear.\n");
4461 context_apply_clear_state(context, This, target, depth_stencil);
4463 target->get_drawable_size(context, &drawable_width, &drawable_height);
4467 /* Only set the values up once, as they are not changing */
4468 if (Flags & WINED3DCLEAR_STENCIL)
4470 if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
4472 glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
4473 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
4476 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
4477 glClearStencil(Stencil);
4478 checkGLcall("glClearStencil");
4479 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4482 if (Flags & WINED3DCLEAR_ZBUFFER)
4484 DWORD location = context->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4486 if (location == SFLAG_DS_ONSCREEN && depth_stencil != This->onscreen_depth_stencil)
4487 device_switch_onscreen_ds(This, context, depth_stencil);
4488 prepare_ds_clear(depth_stencil, context, location, &draw_rect, Count, clear_rect);
4489 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)depth_stencil, SFLAG_INDRAWABLE, TRUE);
4491 glDepthMask(GL_TRUE);
4492 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4494 checkGLcall("glClearDepth");
4495 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4498 if (Flags & WINED3DCLEAR_TARGET)
4500 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)target, SFLAG_INDRAWABLE, TRUE);
4502 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
4504 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
4505 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
4506 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
4507 glClearColor(D3DCOLOR_R(Color), D3DCOLOR_G(Color), D3DCOLOR_B(Color), D3DCOLOR_A(Color));
4508 checkGLcall("glClearColor");
4509 glMask = glMask | GL_COLOR_BUFFER_BIT;
4514 if (context->render_offscreen)
4516 glScissor(draw_rect.left, draw_rect.top,
4517 draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top);
4521 glScissor(draw_rect.left, drawable_height - draw_rect.bottom,
4522 draw_rect.right - draw_rect.left, draw_rect.bottom - draw_rect.top);
4524 checkGLcall("glScissor");
4526 checkGLcall("glClear");
4532 /* Now process each rect in turn. */
4533 for (i = 0; i < Count; ++i)
4535 /* Note gl uses lower left, width/height */
4536 IntersectRect(¤t_rect, &draw_rect, &clear_rect[i]);
4538 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
4539 wine_dbgstr_rect(&clear_rect[i]),
4540 wine_dbgstr_rect(¤t_rect));
4542 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4543 * The rectangle is not cleared, no error is returned, but further rectanlges are
4544 * still cleared if they are valid. */
4545 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
4547 TRACE("Rectangle with negative dimensions, ignoring.\n");
4551 if (context->render_offscreen)
4553 glScissor(current_rect.left, current_rect.top,
4554 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
4558 glScissor(current_rect.left, drawable_height - current_rect.bottom,
4559 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
4561 checkGLcall("glScissor");
4564 checkGLcall("glClear");
4570 if (wined3d_settings.strict_draw_ordering || ((target->Flags & SFLAG_SWAPCHAIN)
4571 && ((IWineD3DSwapChainImpl *)target->container)->front_buffer == target))
4572 wglFlush(); /* Flush to ensure ordering across contexts. */
4574 context_release(context);
4579 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count,
4580 const WINED3DRECT *pRects, DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil)
4582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4584 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4585 Count, pRects, Flags, Color, Z, Stencil);
4587 if (Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && !This->depth_stencil)
4589 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4590 /* TODO: What about depth stencil buffers without stencil bits? */
4591 return WINED3DERR_INVALIDCALL;
4594 return IWineD3DDeviceImpl_ClearSurface(This, This->render_targets[0], Count, pRects, Flags, Color, Z, Stencil);
4601 static void WINAPI IWineD3DDeviceImpl_SetPrimitiveType(IWineD3DDevice *iface,
4602 WINED3DPRIMITIVETYPE primitive_type)
4604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4606 TRACE("iface %p, primitive_type %s\n", iface, debug_d3dprimitivetype(primitive_type));
4608 This->updateStateBlock->changed.primitive_type = TRUE;
4609 This->updateStateBlock->gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4612 static void WINAPI IWineD3DDeviceImpl_GetPrimitiveType(IWineD3DDevice *iface,
4613 WINED3DPRIMITIVETYPE *primitive_type)
4615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4617 TRACE("iface %p, primitive_type %p\n", iface, primitive_type);
4619 *primitive_type = d3d_primitive_type_from_gl(This->stateBlock->gl_primitive_type);
4621 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4624 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, UINT StartVertex, UINT vertex_count)
4626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4628 TRACE("(%p) : start %u, count %u\n", This, StartVertex, vertex_count);
4630 if(!This->stateBlock->vertexDecl) {
4631 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4632 return WINED3DERR_INVALIDCALL;
4635 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4636 if(This->stateBlock->streamIsUP) {
4637 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4638 This->stateBlock->streamIsUP = FALSE;
4641 if(This->stateBlock->loadBaseVertexIndex != 0) {
4642 This->stateBlock->loadBaseVertexIndex = 0;
4643 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4645 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4646 drawPrimitive(iface, vertex_count, StartVertex /* start_idx */, 0 /* indxSize */, NULL /* indxData */);
4650 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface, UINT startIndex, UINT index_count)
4652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4654 IWineD3DBuffer *pIB;
4657 pIB = This->stateBlock->pIndexData;
4659 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4660 * without an index buffer set. (The first time at least...)
4661 * D3D8 simply dies, but I doubt it can do much harm to return
4662 * D3DERR_INVALIDCALL there as well. */
4663 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4664 return WINED3DERR_INVALIDCALL;
4667 if(!This->stateBlock->vertexDecl) {
4668 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4669 return WINED3DERR_INVALIDCALL;
4672 if(This->stateBlock->streamIsUP) {
4673 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4674 This->stateBlock->streamIsUP = FALSE;
4676 vbo = ((struct wined3d_buffer *) pIB)->buffer_object;
4678 TRACE("(%p) : startIndex %u, index count %u.\n", This, startIndex, index_count);
4680 if (This->stateBlock->IndexFmt == WINED3DFMT_R16_UINT) {
4686 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4687 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4688 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4691 drawPrimitive(iface, index_count, startIndex, idxStride,
4692 vbo ? NULL : ((struct wined3d_buffer *)pIB)->resource.allocatedMemory);
4697 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, UINT vertex_count,
4698 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4700 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4703 TRACE("(%p) : vertex count %u, pVtxData %p, stride %u\n",
4704 This, vertex_count, pVertexStreamZeroData, VertexStreamZeroStride);
4706 if(!This->stateBlock->vertexDecl) {
4707 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4708 return WINED3DERR_INVALIDCALL;
4711 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4712 vb = This->stateBlock->streamSource[0];
4713 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4714 if (vb) IWineD3DBuffer_Release(vb);
4715 This->stateBlock->streamOffset[0] = 0;
4716 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4717 This->stateBlock->streamIsUP = TRUE;
4718 This->stateBlock->loadBaseVertexIndex = 0;
4720 /* TODO: Only mark dirty if drawing from a different UP address */
4721 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4723 drawPrimitive(iface, vertex_count, 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */);
4725 /* MSDN specifies stream zero settings must be set to NULL */
4726 This->stateBlock->streamStride[0] = 0;
4727 This->stateBlock->streamSource[0] = NULL;
4729 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4730 * the new stream sources or use UP drawing again
4735 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface,
4736 UINT index_count, const void *pIndexData, WINED3DFORMAT IndexDataFormat,
4737 const void *pVertexStreamZeroData, UINT VertexStreamZeroStride)
4740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4744 TRACE("(%p) : index count %u, pidxdata %p, IdxFmt %u, pVtxdata %p, stride=%u.\n",
4745 This, index_count, pIndexData, IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4747 if(!This->stateBlock->vertexDecl) {
4748 WARN("(%p) : Called without a valid vertex declaration set\n", This);
4749 return WINED3DERR_INVALIDCALL;
4752 if (IndexDataFormat == WINED3DFMT_R16_UINT) {
4758 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4759 vb = This->stateBlock->streamSource[0];
4760 This->stateBlock->streamSource[0] = (IWineD3DBuffer *)pVertexStreamZeroData;
4761 if (vb) IWineD3DBuffer_Release(vb);
4762 This->stateBlock->streamIsUP = TRUE;
4763 This->stateBlock->streamOffset[0] = 0;
4764 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4766 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4767 This->stateBlock->baseVertexIndex = 0;
4768 This->stateBlock->loadBaseVertexIndex = 0;
4769 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4770 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4771 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4773 drawPrimitive(iface, index_count, 0 /* start_idx */, idxStride, pIndexData);
4775 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4776 This->stateBlock->streamSource[0] = NULL;
4777 This->stateBlock->streamStride[0] = 0;
4778 ib = This->stateBlock->pIndexData;
4780 IWineD3DBuffer_Release(ib);
4781 This->stateBlock->pIndexData = NULL;
4783 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4784 * SetStreamSource to specify a vertex buffer
4790 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
4791 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData)
4793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4795 /* Mark the state dirty until we have nicer tracking
4796 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4799 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4800 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4801 This->stateBlock->baseVertexIndex = 0;
4802 This->up_strided = DrawPrimStrideData;
4803 drawPrimitive(iface, vertex_count, 0, 0, NULL);
4804 This->up_strided = NULL;
4808 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
4809 UINT vertex_count, const WineDirect3DVertexStridedData *DrawPrimStrideData,
4810 UINT NumVertices, const void *pIndexData, WINED3DFORMAT IndexDataFormat)
4812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4813 DWORD idxSize = (IndexDataFormat == WINED3DFMT_R32_UINT ? 4 : 2);
4815 /* Mark the state dirty until we have nicer tracking
4816 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4819 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4820 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4821 This->stateBlock->streamIsUP = TRUE;
4822 This->stateBlock->baseVertexIndex = 0;
4823 This->up_strided = DrawPrimStrideData;
4824 drawPrimitive(iface, vertex_count, 0 /* start_idx */, idxSize, pIndexData);
4825 This->up_strided = NULL;
4829 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4830 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface,
4831 IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume)
4833 WINED3DLOCKED_BOX src;
4834 WINED3DLOCKED_BOX dst;
4837 TRACE("iface %p, src_volume %p, dst_volume %p.\n",
4838 iface, pSourceVolume, pDestinationVolume);
4840 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
4841 * dirtification to improve loading performance.
4843 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
4844 if(FAILED(hr)) return hr;
4845 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
4847 IWineD3DVolume_UnlockBox(pSourceVolume);
4851 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
4853 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
4855 IWineD3DVolume_UnlockBox(pSourceVolume);
4857 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
4862 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture(IWineD3DDevice *iface,
4863 IWineD3DBaseTexture *src_texture, IWineD3DBaseTexture *dst_texture)
4865 unsigned int level_count, i;
4866 WINED3DRESOURCETYPE type;
4869 TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
4871 /* Verify that the source and destination textures are non-NULL. */
4872 if (!src_texture || !dst_texture)
4874 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4875 return WINED3DERR_INVALIDCALL;
4878 if (src_texture == dst_texture)
4880 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4881 return WINED3DERR_INVALIDCALL;
4884 /* Verify that the source and destination textures are the same type. */
4885 type = IWineD3DBaseTexture_GetType(src_texture);
4886 if (IWineD3DBaseTexture_GetType(dst_texture) != type)
4888 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4889 return WINED3DERR_INVALIDCALL;
4892 /* Check that both textures have the identical numbers of levels. */
4893 level_count = IWineD3DBaseTexture_GetLevelCount(src_texture);
4894 if (IWineD3DBaseTexture_GetLevelCount(dst_texture) != level_count)
4896 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4897 return WINED3DERR_INVALIDCALL;
4900 /* Make sure that the destination texture is loaded. */
4901 ((IWineD3DBaseTextureImpl *)dst_texture)->baseTexture.internal_preload(dst_texture, SRGB_RGB);
4903 /* Update every surface level of the texture. */
4906 case WINED3DRTYPE_TEXTURE:
4908 IWineD3DSurface *src_surface;
4909 IWineD3DSurface *dst_surface;
4911 for (i = 0; i < level_count; ++i)
4913 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)src_texture, i, &src_surface);
4914 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)dst_texture, i, &dst_surface);
4915 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4916 IWineD3DSurface_Release(dst_surface);
4917 IWineD3DSurface_Release(src_surface);
4920 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4927 case WINED3DRTYPE_CUBETEXTURE:
4929 IWineD3DSurface *src_surface;
4930 IWineD3DSurface *dst_surface;
4931 WINED3DCUBEMAP_FACES face;
4933 for (i = 0; i < level_count; ++i)
4935 /* Update each cube face. */
4936 for (face = WINED3DCUBEMAP_FACE_POSITIVE_X; face <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++face)
4938 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)src_texture,
4939 face, i, &src_surface);
4940 if (FAILED(hr)) ERR("Failed to get src cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4941 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)dst_texture,
4942 face, i, &dst_surface);
4943 if (FAILED(hr)) ERR("Failed to get dst cube surface face %u, level %u, hr %#x.\n", face, i, hr);
4944 hr = IWineD3DDevice_UpdateSurface(iface, src_surface, NULL, dst_surface, NULL);
4945 IWineD3DSurface_Release(dst_surface);
4946 IWineD3DSurface_Release(src_surface);
4949 WARN("IWineD3DDevice_UpdateSurface failed, hr %#x.\n", hr);
4957 case WINED3DRTYPE_VOLUMETEXTURE:
4959 IWineD3DVolume *src_volume;
4960 IWineD3DVolume *dst_volume;
4962 for (i = 0; i < level_count; ++i)
4964 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)src_texture, i, &src_volume);
4965 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)dst_texture, i, &dst_volume);
4966 hr = IWineD3DDeviceImpl_UpdateVolume(iface, src_volume, dst_volume);
4967 IWineD3DVolume_Release(dst_volume);
4968 IWineD3DVolume_Release(src_volume);
4971 WARN("IWineD3DDeviceImpl_UpdateVolume failed, hr %#x.\n", hr);
4979 FIXME("Unsupported texture type %#x.\n", type);
4980 return WINED3DERR_INVALIDCALL;
4986 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4987 IWineD3DSwapChain *swapChain;
4989 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4990 if(hr == WINED3D_OK) {
4991 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4992 IWineD3DSwapChain_Release(swapChain);
4997 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4999 IWineD3DBaseTextureImpl *texture;
5002 TRACE("(%p) : %p\n", This, pNumPasses);
5004 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5005 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5006 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5007 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5009 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5010 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5011 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5014 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5015 if (!texture || texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5017 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5018 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5021 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5022 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5025 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5026 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5027 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5032 /* return a sensible default */
5035 TRACE("returning D3D_OK\n");
5039 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5043 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5045 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5046 if (texture && (texture->resource.format_desc->format == WINED3DFMT_P8_UINT
5047 || texture->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM))
5049 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5054 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5058 PALETTEENTRY **palettes;
5060 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5062 if (PaletteNumber >= MAX_PALETTES) {
5063 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5064 return WINED3DERR_INVALIDCALL;
5067 if (PaletteNumber >= This->NumberOfPalettes) {
5068 NewSize = This->NumberOfPalettes;
5071 } while(PaletteNumber >= NewSize);
5072 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5074 ERR("Out of memory!\n");
5075 return E_OUTOFMEMORY;
5077 This->palettes = palettes;
5078 This->NumberOfPalettes = NewSize;
5081 if (!This->palettes[PaletteNumber]) {
5082 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5083 if (!This->palettes[PaletteNumber]) {
5084 ERR("Out of memory!\n");
5085 return E_OUTOFMEMORY;
5089 for (j = 0; j < 256; ++j) {
5090 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5091 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5092 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5093 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5095 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5096 TRACE("(%p) : returning\n", This);
5100 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5103 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5104 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5105 /* What happens in such situation isn't documented; Native seems to silently abort
5106 on such conditions. Return Invalid Call. */
5107 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5108 return WINED3DERR_INVALIDCALL;
5110 for (j = 0; j < 256; ++j) {
5111 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5112 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5113 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5114 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5116 TRACE("(%p) : returning\n", This);
5120 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5122 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5123 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5124 (tested with reference rasterizer). Return Invalid Call. */
5125 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5126 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5127 return WINED3DERR_INVALIDCALL;
5129 /*TODO: stateblocks */
5130 if (This->currentPalette != PaletteNumber) {
5131 This->currentPalette = PaletteNumber;
5132 dirtify_p8_texture_samplers(This);
5134 TRACE("(%p) : returning\n", This);
5138 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5140 if (PaletteNumber == NULL) {
5141 WARN("(%p) : returning Invalid Call\n", This);
5142 return WINED3DERR_INVALIDCALL;
5144 /*TODO: stateblocks */
5145 *PaletteNumber = This->currentPalette;
5146 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5150 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5155 FIXME("(%p) : stub\n", This);
5159 This->softwareVertexProcessing = bSoftware;
5164 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5169 FIXME("(%p) : stub\n", This);
5172 return This->softwareVertexProcessing;
5175 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface,
5176 UINT swapchain_idx, WINED3DRASTER_STATUS *raster_status)
5178 IWineD3DSwapChain *swapchain;
5181 TRACE("iface %p, swapchain_idx %u, raster_status %p.\n",
5182 iface, swapchain_idx, raster_status);
5184 hr = IWineD3DDeviceImpl_GetSwapChain(iface, swapchain_idx, &swapchain);
5187 WARN("Failed to get swapchain %u, hr %#x.\n", swapchain_idx, hr);
5191 hr = IWineD3DSwapChain_GetRasterStatus(swapchain, raster_status);
5192 IWineD3DSwapChain_Release(swapchain);
5195 WARN("Failed to get raster status, hr %#x.\n", hr);
5202 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments)
5205 if(nSegments != 0.0f) {
5208 FIXME("iface %p, nSegments %.8e stub!\n", iface, nSegments);
5215 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface)
5220 FIXME("iface %p stub!\n", iface);
5226 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
5227 IWineD3DSurface *src_surface, const RECT *src_rect,
5228 IWineD3DSurface *dst_surface, const POINT *dst_point)
5230 IWineD3DSurfaceImpl *src_impl = (IWineD3DSurfaceImpl *)src_surface;
5231 IWineD3DSurfaceImpl *dst_impl = (IWineD3DSurfaceImpl *)dst_surface;
5232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5233 const struct wined3d_format_desc *src_format;
5234 const struct wined3d_format_desc *dst_format;
5235 const struct wined3d_gl_info *gl_info;
5236 struct wined3d_context *context;
5237 const unsigned char *data;
5238 UINT update_w, update_h;
5239 CONVERT_TYPES convert;
5243 struct wined3d_format_desc desc;
5245 TRACE("iface %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
5246 iface, src_surface, wine_dbgstr_rect(src_rect),
5247 dst_surface, wine_dbgstr_point(dst_point));
5249 if (src_impl->resource.pool != WINED3DPOOL_SYSTEMMEM || dst_impl->resource.pool != WINED3DPOOL_DEFAULT)
5251 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
5252 src_surface, dst_surface);
5253 return WINED3DERR_INVALIDCALL;
5256 src_format = src_impl->resource.format_desc;
5257 dst_format = dst_impl->resource.format_desc;
5259 if (src_format->format != dst_format->format)
5261 WARN("Source and destination surfaces should have the same format.\n");
5262 return WINED3DERR_INVALIDCALL;
5265 dst_x = dst_point ? dst_point->x : 0;
5266 dst_y = dst_point ? dst_point->y : 0;
5268 /* This call loads the OpenGL surface directly, instead of copying the
5269 * surface to the destination's sysmem copy. If surface conversion is
5270 * needed, use BltFast instead to copy in sysmem and use regular surface
5272 d3dfmt_get_conv(dst_impl, FALSE, TRUE, &desc, &convert);
5273 if (convert != NO_CONVERSION || desc.convert)
5274 return IWineD3DSurface_BltFast(dst_surface, dst_x, dst_y, src_surface, src_rect, 0);
5276 context = context_acquire(This, NULL);
5277 gl_info = context->gl_info;
5280 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5281 checkGLcall("glActiveTextureARB");
5284 /* Make sure the surface is loaded and up to date */
5285 surface_internal_preload(dst_impl, SRGB_RGB);
5286 IWineD3DSurface_BindTexture(dst_surface, FALSE);
5288 src_w = src_impl->currentDesc.Width;
5289 src_h = src_impl->currentDesc.Height;
5290 update_w = src_rect ? src_rect->right - src_rect->left : src_w;
5291 update_h = src_rect ? src_rect->bottom - src_rect->top : src_h;
5293 data = IWineD3DSurface_GetData(src_surface);
5294 if (!data) ERR("Source surface has no allocated memory, but should be a sysmem surface.\n");
5298 if (dst_format->Flags & WINED3DFMT_FLAG_COMPRESSED)
5300 UINT row_length = (update_w / src_format->block_width) * src_format->block_byte_count;
5301 UINT row_count = update_h / src_format->block_height;
5302 UINT src_pitch = IWineD3DSurface_GetPitch(src_surface);
5306 data += (src_rect->top / src_format->block_height) * src_pitch;
5307 data += (src_rect->left / src_format->block_width) * src_format->block_byte_count;
5310 TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
5311 "format %#x, image_size %#x, data %p.\n", dst_impl->texture_target, dst_impl->texture_level,
5312 dst_x, dst_y, update_w, update_h, dst_format->glFormat, row_count * row_length, data);
5314 if (row_length == src_pitch)
5316 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5317 dst_x, dst_y, update_w, update_h, dst_format->glInternal, row_count * row_length, data));
5323 /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
5324 * can't use the unpack row length like below. */
5325 for (row = 0, y = dst_y; row < row_count; ++row)
5327 GL_EXTCALL(glCompressedTexSubImage2DARB(dst_impl->texture_target, dst_impl->texture_level,
5328 dst_x, y, update_w, src_format->block_height, dst_format->glInternal, row_length, data));
5329 y += src_format->block_height;
5333 checkGLcall("glCompressedTexSubImage2DARB");
5339 data += src_rect->top * src_w * src_format->byte_count;
5340 data += src_rect->left * src_format->byte_count;
5343 TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, data %p.\n",
5344 dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5345 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5347 glPixelStorei(GL_UNPACK_ROW_LENGTH, src_w);
5348 glTexSubImage2D(dst_impl->texture_target, dst_impl->texture_level, dst_x, dst_y,
5349 update_w, update_h, dst_format->glFormat, dst_format->glType, data);
5350 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5351 checkGLcall("glTexSubImage2D");
5355 context_release(context);
5357 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INTEXTURE, TRUE);
5358 sampler = This->rev_tex_unit_map[0];
5359 if (sampler != WINED3D_UNMAPPED_STAGE)
5361 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5367 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5368 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5369 struct WineD3DRectPatch *patch;
5370 GLenum old_primitive_type;
5374 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5376 if(!(Handle || pRectPatchInfo)) {
5377 /* TODO: Write a test for the return value, thus the FIXME */
5378 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5379 return WINED3DERR_INVALIDCALL;
5383 i = PATCHMAP_HASHFUNC(Handle);
5385 LIST_FOR_EACH(e, &This->patches[i]) {
5386 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5387 if(patch->Handle == Handle) {
5394 TRACE("Patch does not exist. Creating a new one\n");
5395 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5396 patch->Handle = Handle;
5397 list_add_head(&This->patches[i], &patch->entry);
5399 TRACE("Found existing patch %p\n", patch);
5402 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5403 * attributes we have to tesselate, read back, and draw. This needs a patch
5404 * management structure instance. Create one.
5406 * A possible improvement is to check if a vertex shader is used, and if not directly
5409 FIXME("Drawing an uncached patch. This is slow\n");
5410 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5413 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5414 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5415 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5417 TRACE("Tesselation density or patch info changed, retesselating\n");
5419 if(pRectPatchInfo) {
5420 patch->RectPatchInfo = *pRectPatchInfo;
5422 patch->numSegs[0] = pNumSegs[0];
5423 patch->numSegs[1] = pNumSegs[1];
5424 patch->numSegs[2] = pNumSegs[2];
5425 patch->numSegs[3] = pNumSegs[3];
5427 hr = tesselate_rectpatch(This, patch);
5429 WARN("Patch tesselation failed\n");
5431 /* Do not release the handle to store the params of the patch */
5433 HeapFree(GetProcessHeap(), 0, patch);
5439 This->currentPatch = patch;
5440 old_primitive_type = This->stateBlock->gl_primitive_type;
5441 This->stateBlock->gl_primitive_type = GL_TRIANGLES;
5442 IWineD3DDevice_DrawPrimitiveStrided(iface, patch->numSegs[0] * patch->numSegs[1] * 2 * 3, &patch->strided);
5443 This->stateBlock->gl_primitive_type = old_primitive_type;
5444 This->currentPatch = NULL;
5446 /* Destroy uncached patches */
5448 HeapFree(GetProcessHeap(), 0, patch->mem);
5449 HeapFree(GetProcessHeap(), 0, patch);
5454 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface,
5455 UINT handle, const float *segment_count, const WINED3DTRIPATCH_INFO *patch_info)
5457 FIXME("iface %p, handle %#x, segment_count %p, patch_info %p stub!\n",
5458 iface, handle, segment_count, patch_info);
5463 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5466 struct WineD3DRectPatch *patch;
5468 TRACE("(%p) Handle(%d)\n", This, Handle);
5470 i = PATCHMAP_HASHFUNC(Handle);
5471 LIST_FOR_EACH(e, &This->patches[i]) {
5472 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5473 if(patch->Handle == Handle) {
5474 TRACE("Deleting patch %p\n", patch);
5475 list_remove(&patch->entry);
5476 HeapFree(GetProcessHeap(), 0, patch->mem);
5477 HeapFree(GetProcessHeap(), 0, patch);
5482 /* TODO: Write a test for the return value */
5483 FIXME("Attempt to destroy nonexistent patch\n");
5484 return WINED3DERR_INVALIDCALL;
5487 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurfaceImpl *surface,
5488 const WINED3DRECT *rect, const float color[4])
5490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5491 struct wined3d_context *context;
5493 if (rect) IWineD3DSurface_LoadLocation((IWineD3DSurface *)surface, SFLAG_INDRAWABLE, NULL);
5494 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)surface, SFLAG_INDRAWABLE, TRUE);
5496 context = context_acquire(This, surface);
5497 context_apply_clear_state(context, This, surface, NULL);
5503 if (surface_is_offscreen(surface))
5504 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5506 glScissor(rect->x1, surface->currentDesc.Height - rect->y2,
5507 rect->x2 - rect->x1, rect->y2 - rect->y1);
5508 checkGLcall("glScissor");
5512 glDisable(GL_SCISSOR_TEST);
5515 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5516 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
5518 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
5519 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
5521 glClearColor(color[0], color[1], color[2], color[3]);
5522 glClear(GL_COLOR_BUFFER_BIT);
5523 checkGLcall("glClear");
5527 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5529 context_release(context);
5532 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface,
5533 IWineD3DSurface *pSurface, const WINED3DRECT *pRect, WINED3DCOLOR color)
5535 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5538 TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, pSurface, pRect, color);
5540 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5541 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5542 return WINED3DERR_INVALIDCALL;
5545 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5546 const float c[4] = {D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color)};
5547 color_fill_fbo(iface, surface, pRect, c);
5550 /* Just forward this to the DirectDraw blitting engine */
5551 memset(&BltFx, 0, sizeof(BltFx));
5552 BltFx.dwSize = sizeof(BltFx);
5553 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(color, surface->resource.format_desc->format);
5554 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
5555 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5559 static void WINAPI IWineD3DDeviceImpl_ClearRendertargetView(IWineD3DDevice *iface,
5560 IWineD3DRendertargetView *rendertarget_view, const float color[4])
5562 IWineD3DResource *resource;
5563 IWineD3DSurfaceImpl *surface;
5566 hr = IWineD3DRendertargetView_GetResource(rendertarget_view, &resource);
5569 ERR("Failed to get resource, hr %#x\n", hr);
5573 if (IWineD3DResource_GetType(resource) != WINED3DRTYPE_SURFACE)
5575 FIXME("Only supported on surface resources\n");
5576 IWineD3DResource_Release(resource);
5580 surface = (IWineD3DSurfaceImpl *)resource;
5582 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
5584 color_fill_fbo(iface, surface, NULL, color);
5591 WARN("Converting to WINED3DCOLOR, this might give incorrect results\n");
5593 c = ((DWORD)(color[2] * 255.0f));
5594 c |= ((DWORD)(color[1] * 255.0f)) << 8;
5595 c |= ((DWORD)(color[0] * 255.0f)) << 16;
5596 c |= ((DWORD)(color[3] * 255.0f)) << 24;
5598 /* Just forward this to the DirectDraw blitting engine */
5599 memset(&BltFx, 0, sizeof(BltFx));
5600 BltFx.dwSize = sizeof(BltFx);
5601 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(c, surface->resource.format_desc->format);
5602 hr = IWineD3DSurface_Blt((IWineD3DSurface *)surface, NULL, NULL, NULL,
5603 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
5606 ERR("Blt failed, hr %#x\n", hr);
5610 IWineD3DResource_Release(resource);
5613 /* rendertarget and depth stencil functions */
5614 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5617 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5619 ERR("(%p) : Only %d render targets are supported.\n",
5620 This, This->adapter->gl_info.limits.buffers);
5621 return WINED3DERR_INVALIDCALL;
5624 *ppRenderTarget = (IWineD3DSurface *)This->render_targets[RenderTargetIndex];
5625 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5626 /* Note inc ref on returned surface */
5627 if(*ppRenderTarget != NULL)
5628 IWineD3DSurface_AddRef(*ppRenderTarget);
5632 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface,
5633 IWineD3DSurface *front, IWineD3DSurface *back)
5635 IWineD3DSurfaceImpl *front_impl = (IWineD3DSurfaceImpl *)front;
5636 IWineD3DSurfaceImpl *back_impl = (IWineD3DSurfaceImpl *)back;
5637 IWineD3DSwapChainImpl *swapchain;
5640 TRACE("iface %p, front %p, back %p.\n", iface, front, back);
5642 if (FAILED(hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **)&swapchain)))
5644 ERR("Failed to get the swapchain, hr %#x.\n", hr);
5648 if (front_impl && !(front_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5650 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5651 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5652 return WINED3DERR_INVALIDCALL;
5657 if (!(back_impl->resource.usage & WINED3DUSAGE_RENDERTARGET))
5659 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage.\n");
5660 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5661 return WINED3DERR_INVALIDCALL;
5664 if (!swapchain->back_buffers)
5666 swapchain->back_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*swapchain->back_buffers));
5667 if (!swapchain->back_buffers)
5669 ERR("Failed to allocate back buffer array memory.\n");
5670 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5671 return E_OUTOFMEMORY;
5676 if (swapchain->front_buffer != front_impl)
5678 TRACE("Changing the front buffer from %p to %p.\n", swapchain->front_buffer, front_impl);
5680 if (swapchain->front_buffer)
5682 IWineD3DSurface_SetContainer((IWineD3DSurface *)swapchain->front_buffer, NULL);
5683 swapchain->front_buffer->Flags &= ~SFLAG_SWAPCHAIN;
5685 swapchain->front_buffer = front_impl;
5689 IWineD3DSurface_SetContainer(front, (IWineD3DBase *)swapchain);
5690 front_impl->Flags |= SFLAG_SWAPCHAIN;
5694 if (swapchain->back_buffers[0] != back_impl)
5696 TRACE("Changing the back buffer from %p to %p.\n", swapchain->back_buffers[0], back_impl);
5698 if (swapchain->back_buffers[0])
5700 IWineD3DSurface_SetContainer((IWineD3DSurface *)swapchain->back_buffers[0], NULL);
5701 swapchain->back_buffers[0]->Flags &= ~SFLAG_SWAPCHAIN;
5703 swapchain->back_buffers[0] = back_impl;
5707 swapchain->presentParms.BackBufferWidth = back_impl->currentDesc.Width;
5708 swapchain->presentParms.BackBufferHeight = back_impl->currentDesc.Height;
5709 swapchain->presentParms.BackBufferFormat = back_impl->resource.format_desc->format;
5710 swapchain->presentParms.BackBufferCount = 1;
5712 IWineD3DSurface_SetContainer(back, (IWineD3DBase *)swapchain);
5713 back_impl->Flags |= SFLAG_SWAPCHAIN;
5717 swapchain->presentParms.BackBufferCount = 0;
5718 HeapFree(GetProcessHeap(), 0, swapchain->back_buffers);
5719 swapchain->back_buffers = NULL;
5723 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
5727 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5729 *ppZStencilSurface = (IWineD3DSurface *)This->depth_stencil;
5730 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5732 if(*ppZStencilSurface != NULL) {
5733 /* Note inc ref on returned surface */
5734 IWineD3DSurface_AddRef(*ppZStencilSurface);
5737 return WINED3DERR_NOTFOUND;
5741 void stretch_rect_fbo(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *src_surface, const RECT *src_rect_in,
5742 IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect_in, const WINED3DTEXTUREFILTERTYPE filter)
5744 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5745 const struct wined3d_gl_info *gl_info;
5746 struct wined3d_context *context;
5748 RECT src_rect, dst_rect;
5750 TRACE("device %p, src_surface %p, src_rect_in %s, dst_surface %p, dst_rect_in %s, filter %s (0x%08x).\n",
5751 device, src_surface, wine_dbgstr_rect(src_rect_in), dst_surface,
5752 wine_dbgstr_rect(dst_rect_in), debug_d3dtexturefiltertype(filter), filter);
5754 src_rect = *src_rect_in;
5755 dst_rect = *dst_rect_in;
5758 case WINED3DTEXF_LINEAR:
5759 gl_filter = GL_LINEAR;
5763 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5764 case WINED3DTEXF_NONE:
5765 case WINED3DTEXF_POINT:
5766 gl_filter = GL_NEAREST;
5770 /* Make sure the drawables are up-to-date. Note that loading the
5771 * destination surface isn't strictly required if we overwrite the
5772 * entire surface. */
5773 IWineD3DSurface_LoadLocation((IWineD3DSurface *)src_surface, SFLAG_INDRAWABLE, NULL);
5774 IWineD3DSurface_LoadLocation((IWineD3DSurface *)dst_surface, SFLAG_INDRAWABLE, NULL);
5776 if (!surface_is_offscreen(src_surface)) context = context_acquire(device, src_surface);
5777 else if (!surface_is_offscreen(dst_surface)) context = context_acquire(device, dst_surface);
5778 else context = context_acquire(device, NULL);
5780 if (!context->valid)
5782 context_release(context);
5783 WARN("Invalid context, skipping blit.\n");
5787 gl_info = context->gl_info;
5789 if (!surface_is_offscreen(src_surface))
5791 GLenum buffer = surface_get_gl_buffer(src_surface);
5793 TRACE("Source surface %p is onscreen\n", src_surface);
5795 if (buffer == GL_FRONT)
5796 surface_translate_frontbuffer_coords(src_surface, context->win_handle, &src_rect);
5798 src_rect.top = src_surface->currentDesc.Height - src_rect.top;
5799 src_rect.bottom = src_surface->currentDesc.Height - src_rect.bottom;
5802 context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5803 glReadBuffer(buffer);
5804 checkGLcall("glReadBuffer()");
5806 TRACE("Source surface %p is offscreen\n", src_surface);
5808 context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL);
5809 glReadBuffer(GL_COLOR_ATTACHMENT0);
5810 checkGLcall("glReadBuffer()");
5814 /* Attach dst surface to dst fbo */
5815 if (!surface_is_offscreen(dst_surface))
5817 GLenum buffer = surface_get_gl_buffer(dst_surface);
5819 TRACE("Destination surface %p is onscreen\n", dst_surface);
5821 if (buffer == GL_FRONT)
5822 surface_translate_frontbuffer_coords(dst_surface, context->win_handle, &dst_rect);
5824 dst_rect.top = dst_surface->currentDesc.Height - dst_rect.top;
5825 dst_rect.bottom = dst_surface->currentDesc.Height - dst_rect.bottom;
5828 context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5829 context_set_draw_buffer(context, buffer);
5833 TRACE("Destination surface %p is offscreen\n", dst_surface);
5836 context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL);
5837 context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5839 glDisable(GL_SCISSOR_TEST);
5840 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5842 gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
5843 dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, mask, gl_filter);
5844 checkGLcall("glBlitFramebuffer()");
5848 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5850 context_release(context);
5852 IWineD3DSurface_ModifyLocation((IWineD3DSurface *)dst_surface, SFLAG_INDRAWABLE, TRUE);
5855 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget,
5856 BOOL set_viewport) {
5857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5859 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5861 if (RenderTargetIndex >= This->adapter->gl_info.limits.buffers)
5863 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
5864 This, RenderTargetIndex, This->adapter->gl_info.limits.buffers);
5865 return WINED3DERR_INVALIDCALL;
5868 /* MSDN says that null disables the render target
5869 but a device must always be associated with a render target
5870 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5872 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5873 FIXME("Trying to set render target 0 to NULL\n");
5874 return WINED3DERR_INVALIDCALL;
5876 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5877 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);
5878 return WINED3DERR_INVALIDCALL;
5881 /* If we are trying to set what we already have, don't bother */
5882 if (pRenderTarget == (IWineD3DSurface *)This->render_targets[RenderTargetIndex])
5884 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5888 IWineD3DSurface_AddRef(pRenderTarget);
5889 if (This->render_targets[RenderTargetIndex])
5890 IWineD3DSurface_Release((IWineD3DSurface *)This->render_targets[RenderTargetIndex]);
5891 This->render_targets[RenderTargetIndex] = (IWineD3DSurfaceImpl *)pRenderTarget;
5893 /* Render target 0 is special */
5894 if(RenderTargetIndex == 0 && set_viewport) {
5895 /* Finally, reset the viewport and scissor rect as the MSDN states.
5896 * Tests show that stateblock recording is ignored, the change goes
5897 * directly into the primary stateblock.
5899 This->stateBlock->viewport.Height = This->render_targets[0]->currentDesc.Height;
5900 This->stateBlock->viewport.Width = This->render_targets[0]->currentDesc.Width;
5901 This->stateBlock->viewport.X = 0;
5902 This->stateBlock->viewport.Y = 0;
5903 This->stateBlock->viewport.MaxZ = 1.0f;
5904 This->stateBlock->viewport.MinZ = 0.0f;
5905 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5907 This->stateBlock->scissorRect.top = 0;
5908 This->stateBlock->scissorRect.left = 0;
5909 This->stateBlock->scissorRect.right = This->stateBlock->viewport.Width;
5910 This->stateBlock->scissorRect.bottom = This->stateBlock->viewport.Height;
5911 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
5916 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5918 IWineD3DSurfaceImpl *tmp;
5920 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n", This, pNewZStencil, This->depth_stencil);
5922 if (This->depth_stencil == (IWineD3DSurfaceImpl *)pNewZStencil)
5924 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
5928 if (This->depth_stencil)
5930 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
5931 || This->depth_stencil->Flags & SFLAG_DISCARD)
5933 surface_modify_ds_location(This->depth_stencil, SFLAG_DS_DISCARDED,
5934 This->depth_stencil->currentDesc.Width,
5935 This->depth_stencil->currentDesc.Height);
5936 if (This->depth_stencil == This->onscreen_depth_stencil)
5938 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
5939 This->onscreen_depth_stencil = NULL;
5944 tmp = This->depth_stencil;
5945 This->depth_stencil = (IWineD3DSurfaceImpl *)pNewZStencil;
5946 if (This->depth_stencil) IWineD3DSurface_AddRef((IWineD3DSurface *)This->depth_stencil);
5947 if (tmp) IWineD3DSurface_Release((IWineD3DSurface *)tmp);
5949 if ((!tmp && pNewZStencil) || (!pNewZStencil && tmp))
5951 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5952 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5953 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5954 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5960 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5961 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5963 /* TODO: the use of Impl is deprecated. */
5964 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5965 WINED3DLOCKED_RECT lockedRect;
5967 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5969 /* some basic validation checks */
5970 if (This->cursorTexture)
5972 struct wined3d_context *context = context_acquire(This, NULL);
5974 glDeleteTextures(1, &This->cursorTexture);
5976 context_release(context);
5977 This->cursorTexture = 0;
5980 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5981 This->haveHardwareCursor = TRUE;
5983 This->haveHardwareCursor = FALSE;
5986 WINED3DLOCKED_RECT rect;
5988 /* MSDN: Cursor must be A8R8G8B8 */
5989 if (pSur->resource.format_desc->format != WINED3DFMT_B8G8R8A8_UNORM)
5991 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5992 return WINED3DERR_INVALIDCALL;
5995 /* MSDN: Cursor must be smaller than the display mode */
5996 if(pSur->currentDesc.Width > This->ddraw_width ||
5997 pSur->currentDesc.Height > This->ddraw_height) {
5998 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);
5999 return WINED3DERR_INVALIDCALL;
6002 if (!This->haveHardwareCursor) {
6003 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6005 /* Do not store the surface's pointer because the application may
6006 * release it after setting the cursor image. Windows doesn't
6007 * addref the set surface, so we can't do this either without
6008 * creating circular refcount dependencies. Copy out the gl texture
6011 This->cursorWidth = pSur->currentDesc.Width;
6012 This->cursorHeight = pSur->currentDesc.Height;
6013 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6015 const struct wined3d_gl_info *gl_info = &This->adapter->gl_info;
6016 const struct wined3d_format_desc *format_desc = getFormatDescEntry(WINED3DFMT_B8G8R8A8_UNORM, gl_info);
6017 struct wined3d_context *context;
6018 char *mem, *bits = rect.pBits;
6019 GLint intfmt = format_desc->glInternal;
6020 GLint format = format_desc->glFormat;
6021 GLint type = format_desc->glType;
6022 INT height = This->cursorHeight;
6023 INT width = This->cursorWidth;
6024 INT bpp = format_desc->byte_count;
6028 /* Reformat the texture memory (pitch and width can be
6030 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6031 for(i = 0; i < height; i++)
6032 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6033 IWineD3DSurface_UnlockRect(pCursorBitmap);
6035 context = context_acquire(This, NULL);
6039 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6041 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6042 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6045 /* Make sure that a proper texture unit is selected */
6046 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6047 checkGLcall("glActiveTextureARB");
6048 sampler = This->rev_tex_unit_map[0];
6049 if (sampler != WINED3D_UNMAPPED_STAGE)
6051 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6053 /* Create a new cursor texture */
6054 glGenTextures(1, &This->cursorTexture);
6055 checkGLcall("glGenTextures");
6056 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6057 checkGLcall("glBindTexture");
6058 /* Copy the bitmap memory into the cursor texture */
6059 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6060 HeapFree(GetProcessHeap(), 0, mem);
6061 checkGLcall("glTexImage2D");
6063 if (gl_info->supported[APPLE_CLIENT_STORAGE])
6065 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6066 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6071 context_release(context);
6075 FIXME("A cursor texture was not returned.\n");
6076 This->cursorTexture = 0;
6081 /* Draw a hardware cursor */
6082 ICONINFO cursorInfo;
6084 /* Create and clear maskBits because it is not needed for
6085 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6087 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6088 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6089 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6090 WINED3DLOCK_NO_DIRTY_UPDATE |
6091 WINED3DLOCK_READONLY
6093 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6094 pSur->currentDesc.Height);
6096 cursorInfo.fIcon = FALSE;
6097 cursorInfo.xHotspot = XHotSpot;
6098 cursorInfo.yHotspot = YHotSpot;
6099 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6101 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width, pSur->currentDesc.Height,
6102 1, 32, lockedRect.pBits);
6103 IWineD3DSurface_UnlockRect(pCursorBitmap);
6104 /* Create our cursor and clean up. */
6105 cursor = CreateIconIndirect(&cursorInfo);
6107 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6108 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6109 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6110 This->hardwareCursor = cursor;
6111 HeapFree(GetProcessHeap(), 0, maskBits);
6115 This->xHotSpot = XHotSpot;
6116 This->yHotSpot = YHotSpot;
6120 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6122 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6124 This->xScreenSpace = XScreenSpace;
6125 This->yScreenSpace = YScreenSpace;
6131 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6133 BOOL oldVisible = This->bCursorVisible;
6136 TRACE("(%p) : visible(%d)\n", This, bShow);
6139 * When ShowCursor is first called it should make the cursor appear at the OS's last
6140 * known cursor position. Because of this, some applications just repetitively call
6141 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6144 This->xScreenSpace = pt.x;
6145 This->yScreenSpace = pt.y;
6147 if (This->haveHardwareCursor) {
6148 This->bCursorVisible = bShow;
6150 SetCursor(This->hardwareCursor);
6156 if (This->cursorTexture)
6157 This->bCursorVisible = bShow;
6163 static HRESULT WINAPI evict_managed_resource(IWineD3DResource *resource, void *data) {
6164 TRACE("checking resource %p for eviction\n", resource);
6165 if(((IWineD3DResourceImpl *) resource)->resource.pool == WINED3DPOOL_MANAGED) {
6166 TRACE("Evicting %p\n", resource);
6167 IWineD3DResource_UnLoad(resource);
6169 IWineD3DResource_Release(resource);
6173 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice *iface)
6175 TRACE("iface %p.\n", iface);
6177 IWineD3DDevice_EnumResources(iface, evict_managed_resource, NULL);
6181 static HRESULT updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6183 IWineD3DDeviceImpl *device = surface->resource.device;
6184 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6186 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6187 if(surface->Flags & SFLAG_DIBSECTION) {
6188 /* Release the DC */
6189 SelectObject(surface->hDC, surface->dib.holdbitmap);
6190 DeleteDC(surface->hDC);
6191 /* Release the DIB section */
6192 DeleteObject(surface->dib.DIBsection);
6193 surface->dib.bitmap_data = NULL;
6194 surface->resource.allocatedMemory = NULL;
6195 surface->Flags &= ~SFLAG_DIBSECTION;
6197 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6198 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6199 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
6200 || gl_info->supported[WINE_NORMALIZED_TEXRECT])
6202 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6203 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6205 surface->pow2Width = surface->pow2Height = 1;
6206 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6207 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6210 if (surface->texture_name)
6212 struct wined3d_context *context = context_acquire(device, NULL);
6214 glDeleteTextures(1, &surface->texture_name);
6216 context_release(context);
6217 surface->texture_name = 0;
6218 surface->Flags &= ~SFLAG_CLIENT;
6220 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6221 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6222 surface->Flags |= SFLAG_NONPOW2;
6224 surface->Flags &= ~SFLAG_NONPOW2;
6226 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6227 surface->resource.allocatedMemory = NULL;
6228 surface->resource.heapMemory = NULL;
6229 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6231 /* Put all surfaces into sysmem - the drawable might disappear if the backbuffer was rendered
6233 if (!surface_init_sysmem(surface))
6235 return E_OUTOFMEMORY;
6240 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6241 TRACE("Unloading resource %p\n", resource);
6242 IWineD3DResource_UnLoad(resource);
6243 IWineD3DResource_Release(resource);
6247 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6250 WINED3DDISPLAYMODE m;
6253 /* All Windowed modes are supported, as is leaving the current mode */
6254 if(pp->Windowed) return TRUE;
6255 if(!pp->BackBufferWidth) return TRUE;
6256 if(!pp->BackBufferHeight) return TRUE;
6258 count = IWineD3D_GetAdapterModeCount(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN);
6259 for(i = 0; i < count; i++) {
6260 memset(&m, 0, sizeof(m));
6261 hr = IWineD3D_EnumAdapterModes(This->wined3d, This->adapter->ordinal, WINED3DFMT_UNKNOWN, i, &m);
6263 ERR("EnumAdapterModes failed\n");
6265 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6266 /* Mode found, it is supported */
6270 /* Mode not found -> not supported */
6274 static void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6277 const struct wined3d_gl_info *gl_info;
6278 struct wined3d_context *context;
6279 IWineD3DBaseShaderImpl *shader;
6281 context = context_acquire(This, NULL);
6282 gl_info = context->gl_info;
6284 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6285 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6286 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6290 if(This->depth_blt_texture) {
6291 glDeleteTextures(1, &This->depth_blt_texture);
6292 This->depth_blt_texture = 0;
6294 if (This->depth_blt_rb) {
6295 gl_info->fbo_ops.glDeleteRenderbuffers(1, &This->depth_blt_rb);
6296 This->depth_blt_rb = 0;
6297 This->depth_blt_rb_w = 0;
6298 This->depth_blt_rb_h = 0;
6302 This->blitter->free_private(iface);
6303 This->frag_pipe->free_private(iface);
6304 This->shader_backend->shader_free_private(iface);
6305 destroy_dummy_textures(This, gl_info);
6307 context_release(context);
6309 while (This->numContexts)
6311 context_destroy(This, This->contexts[0]);
6313 HeapFree(GetProcessHeap(), 0, swapchain->context);
6314 swapchain->context = NULL;
6315 swapchain->num_contexts = 0;
6318 static HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChainImpl *swapchain)
6320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6321 struct wined3d_context *context;
6323 IWineD3DSurfaceImpl *target;
6325 /* Recreate the primary swapchain's context */
6326 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6327 if (!swapchain->context)
6329 ERR("Failed to allocate memory for swapchain context array.\n");
6330 return E_OUTOFMEMORY;
6333 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
6334 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
6336 WARN("Failed to create context.\n");
6337 HeapFree(GetProcessHeap(), 0, swapchain->context);
6341 swapchain->context[0] = context;
6342 swapchain->num_contexts = 1;
6343 create_dummy_textures(This);
6344 context_release(context);
6346 hr = This->shader_backend->shader_alloc_private(iface);
6349 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
6353 hr = This->frag_pipe->alloc_private(iface);
6356 ERR("Failed to allocate fragment pipe private data, hr %#x.\n", hr);
6357 This->shader_backend->shader_free_private(iface);
6361 hr = This->blitter->alloc_private(iface);
6364 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
6365 This->frag_pipe->free_private(iface);
6366 This->shader_backend->shader_free_private(iface);
6373 context_acquire(This, NULL);
6374 destroy_dummy_textures(This, context->gl_info);
6375 context_release(context);
6376 context_destroy(This, context);
6377 HeapFree(GetProcessHeap(), 0, swapchain->context);
6378 swapchain->num_contexts = 0;
6382 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6384 IWineD3DSwapChainImpl *swapchain;
6386 BOOL DisplayModeChanged = FALSE;
6387 WINED3DDISPLAYMODE mode;
6388 TRACE("(%p)\n", This);
6390 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6392 ERR("Failed to get the first implicit swapchain\n");
6396 if(!is_display_mode_supported(This, pPresentationParameters)) {
6397 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6398 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6399 pPresentationParameters->BackBufferHeight);
6400 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
6401 return WINED3DERR_INVALIDCALL;
6404 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6405 * on an existing gl context, so there's no real need for recreation.
6407 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6409 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6411 TRACE("New params:\n");
6412 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6413 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6414 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6415 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6416 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6417 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6418 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6419 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6420 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6421 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6422 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6423 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6424 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6426 /* No special treatment of these parameters. Just store them */
6427 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6428 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6429 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6430 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6432 /* What to do about these? */
6433 if(pPresentationParameters->BackBufferCount != 0 &&
6434 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6435 ERR("Cannot change the back buffer count yet\n");
6437 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6438 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6439 ERR("Cannot change the back buffer format yet\n");
6441 if(pPresentationParameters->hDeviceWindow != NULL &&
6442 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6443 ERR("Cannot change the device window yet\n");
6445 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil)
6449 TRACE("Creating the depth stencil buffer\n");
6451 hrc = IWineD3DDeviceParent_CreateDepthStencilSurface(This->device_parent,
6453 pPresentationParameters->BackBufferWidth,
6454 pPresentationParameters->BackBufferHeight,
6455 pPresentationParameters->AutoDepthStencilFormat,
6456 pPresentationParameters->MultiSampleType,
6457 pPresentationParameters->MultiSampleQuality,
6459 (IWineD3DSurface **)&This->auto_depth_stencil);
6462 ERR("Failed to create the depth stencil buffer\n");
6463 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6464 return WINED3DERR_INVALIDCALL;
6468 if (This->onscreen_depth_stencil)
6470 IWineD3DSurface_Release((IWineD3DSurface *)This->onscreen_depth_stencil);
6471 This->onscreen_depth_stencil = NULL;
6474 /* Reset the depth stencil */
6475 if (pPresentationParameters->EnableAutoDepthStencil)
6476 IWineD3DDevice_SetDepthStencilSurface(iface, (IWineD3DSurface *)This->auto_depth_stencil);
6478 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
6480 TRACE("Resetting stateblock\n");
6481 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
6482 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
6484 delete_opengl_contexts(iface, swapchain);
6486 if(pPresentationParameters->Windowed) {
6487 mode.Width = swapchain->orig_width;
6488 mode.Height = swapchain->orig_height;
6489 mode.RefreshRate = 0;
6490 mode.Format = swapchain->presentParms.BackBufferFormat;
6492 mode.Width = pPresentationParameters->BackBufferWidth;
6493 mode.Height = pPresentationParameters->BackBufferHeight;
6494 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6495 mode.Format = swapchain->presentParms.BackBufferFormat;
6498 /* Should Width == 800 && Height == 0 set 800x600? */
6499 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6500 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6501 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6505 if(!pPresentationParameters->Windowed) {
6506 DisplayModeChanged = TRUE;
6508 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6509 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6511 hr = updateSurfaceDesc(swapchain->front_buffer, pPresentationParameters);
6514 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6518 for (i = 0; i < swapchain->presentParms.BackBufferCount; ++i)
6520 hr = updateSurfaceDesc(swapchain->back_buffers[i], pPresentationParameters);
6523 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6527 if (This->auto_depth_stencil)
6529 hr = updateSurfaceDesc(This->auto_depth_stencil, pPresentationParameters);
6532 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6538 if (!pPresentationParameters->Windowed != !swapchain->presentParms.Windowed
6539 || DisplayModeChanged)
6541 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6543 if (!pPresentationParameters->Windowed)
6545 if(swapchain->presentParms.Windowed) {
6546 /* switch from windowed to fs */
6547 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6548 pPresentationParameters->BackBufferHeight);
6550 /* Fullscreen -> fullscreen mode change */
6551 MoveWindow(swapchain->device_window, 0, 0,
6552 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
6556 else if (!swapchain->presentParms.Windowed)
6558 /* Fullscreen -> windowed switch */
6559 swapchain_restore_fullscreen_window(swapchain);
6561 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6562 } else if(!pPresentationParameters->Windowed) {
6563 DWORD style = This->style, exStyle = This->exStyle;
6564 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
6565 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
6566 * Reset to clear up their mess. Guild Wars also loses the device during that.
6570 swapchain_setup_fullscreen_window(swapchain, pPresentationParameters->BackBufferWidth,
6571 pPresentationParameters->BackBufferHeight);
6572 This->style = style;
6573 This->exStyle = exStyle;
6576 /* Note: No parent needed for initial internal stateblock */
6577 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
6578 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6579 else TRACE("Created stateblock %p\n", This->stateBlock);
6580 This->updateStateBlock = This->stateBlock;
6581 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
6583 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
6585 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
6588 if(wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6591 GetClientRect(swapchain->win_handle, &client_rect);
6593 if(!swapchain->presentParms.BackBufferCount)
6595 TRACE("Single buffered rendering\n");
6596 swapchain->render_to_fbo = FALSE;
6598 else if(swapchain->presentParms.BackBufferWidth != client_rect.right ||
6599 swapchain->presentParms.BackBufferHeight != client_rect.bottom )
6601 TRACE("Rendering to FBO. Backbuffer %ux%u, window %ux%u\n",
6602 swapchain->presentParms.BackBufferWidth,
6603 swapchain->presentParms.BackBufferHeight,
6604 client_rect.right, client_rect.bottom);
6605 swapchain->render_to_fbo = TRUE;
6609 TRACE("Rendering directly to GL_BACK\n");
6610 swapchain->render_to_fbo = FALSE;
6614 hr = create_primary_opengl_context(iface, swapchain);
6615 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6617 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
6623 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL enable_dialogs)
6625 TRACE("iface %p, enable_dialogs %#x.\n", iface, enable_dialogs);
6627 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
6633 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6635 TRACE("(%p) : pParameters %p\n", This, pParameters);
6637 *pParameters = This->createParms;
6641 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6642 IWineD3DSwapChain *swapchain;
6644 TRACE("Relaying to swapchain\n");
6646 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6647 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
6648 IWineD3DSwapChain_Release(swapchain);
6652 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6653 IWineD3DSwapChain *swapchain;
6655 TRACE("Relaying to swapchain\n");
6657 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
6658 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6659 IWineD3DSwapChain_Release(swapchain);
6664 /** ********************************************************
6665 * Notification functions
6666 ** ********************************************************/
6667 /** This function must be called in the release of a resource when ref == 0,
6668 * the contents of resource must still be correct,
6669 * any handles to other resource held by the caller must be closed
6670 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6671 *****************************************************/
6672 void device_resource_add(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6674 TRACE("(%p) : Adding resource %p\n", This, resource);
6676 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6679 static void device_resource_remove(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6681 TRACE("(%p) : Removing resource %p\n", This, resource);
6683 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6686 void device_resource_released(IWineD3DDeviceImpl *This, IWineD3DResource *resource)
6688 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
6691 TRACE("(%p) : resource %p\n", This, resource);
6693 context_resource_released((IWineD3DDevice *)This, resource, type);
6696 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6697 case WINED3DRTYPE_SURFACE: {
6700 if (This->d3d_initialized)
6702 for (i = 0; i < This->adapter->gl_info.limits.buffers; ++i)
6704 if (This->render_targets[i] == (IWineD3DSurfaceImpl *)resource)
6705 This->render_targets[i] = NULL;
6707 if (This->depth_stencil == (IWineD3DSurfaceImpl *)resource)
6708 This->depth_stencil = NULL;
6713 case WINED3DRTYPE_TEXTURE:
6714 case WINED3DRTYPE_CUBETEXTURE:
6715 case WINED3DRTYPE_VOLUMETEXTURE:
6716 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6717 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6718 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6719 This->stateBlock->textures[counter] = NULL;
6721 if (This->updateStateBlock != This->stateBlock ){
6722 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6723 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6724 This->updateStateBlock->textures[counter] = NULL;
6729 case WINED3DRTYPE_VOLUME:
6730 /* TODO: nothing really? */
6732 case WINED3DRTYPE_BUFFER:
6735 TRACE("Cleaning up stream pointers\n");
6737 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6738 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6739 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6741 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6742 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6743 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6744 This->updateStateBlock->streamSource[streamNumber] = 0;
6745 /* Set changed flag? */
6748 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) */
6749 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6750 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6751 This->stateBlock->streamSource[streamNumber] = 0;
6756 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6757 if (This->updateStateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6758 This->updateStateBlock->pIndexData = NULL;
6761 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6762 if (This->stateBlock->pIndexData == (IWineD3DBuffer *)resource) {
6763 This->stateBlock->pIndexData = NULL;
6770 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6775 /* Remove the resource from the resourceStore */
6776 device_resource_remove(This, resource);
6778 TRACE("Resource released\n");
6782 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
6783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6784 IWineD3DResourceImpl *resource, *cursor;
6786 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
6788 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6789 TRACE("enumerating resource %p\n", resource);
6790 IWineD3DResource_AddRef((IWineD3DResource *) resource);
6791 ret = pCallback((IWineD3DResource *) resource, pData);
6792 if(ret == S_FALSE) {
6793 TRACE("Canceling enumeration\n");
6800 static HRESULT WINAPI IWineD3DDeviceImpl_GetSurfaceFromDC(IWineD3DDevice *iface, HDC dc, IWineD3DSurface **surface)
6802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6803 IWineD3DResourceImpl *resource;
6805 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry)
6807 WINED3DRESOURCETYPE type = IWineD3DResource_GetType((IWineD3DResource *)resource);
6808 if (type == WINED3DRTYPE_SURFACE)
6810 if (((IWineD3DSurfaceImpl *)resource)->hDC == dc)
6812 TRACE("Found surface %p for dc %p.\n", resource, dc);
6813 *surface = (IWineD3DSurface *)resource;
6819 return WINED3DERR_INVALIDCALL;
6822 /**********************************************************
6823 * IWineD3DDevice VTbl follows
6824 **********************************************************/
6826 static const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6828 /*** IUnknown methods ***/
6829 IWineD3DDeviceImpl_QueryInterface,
6830 IWineD3DDeviceImpl_AddRef,
6831 IWineD3DDeviceImpl_Release,
6832 /*** IWineD3DDevice methods ***/
6833 IWineD3DDeviceImpl_GetParent,
6834 /*** Creation methods**/
6835 IWineD3DDeviceImpl_CreateBuffer,
6836 IWineD3DDeviceImpl_CreateVertexBuffer,
6837 IWineD3DDeviceImpl_CreateIndexBuffer,
6838 IWineD3DDeviceImpl_CreateStateBlock,
6839 IWineD3DDeviceImpl_CreateSurface,
6840 IWineD3DDeviceImpl_CreateRendertargetView,
6841 IWineD3DDeviceImpl_CreateTexture,
6842 IWineD3DDeviceImpl_CreateVolumeTexture,
6843 IWineD3DDeviceImpl_CreateVolume,
6844 IWineD3DDeviceImpl_CreateCubeTexture,
6845 IWineD3DDeviceImpl_CreateQuery,
6846 IWineD3DDeviceImpl_CreateSwapChain,
6847 IWineD3DDeviceImpl_CreateVertexDeclaration,
6848 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6849 IWineD3DDeviceImpl_CreateVertexShader,
6850 IWineD3DDeviceImpl_CreateGeometryShader,
6851 IWineD3DDeviceImpl_CreatePixelShader,
6852 IWineD3DDeviceImpl_CreatePalette,
6853 /*** Odd functions **/
6854 IWineD3DDeviceImpl_Init3D,
6855 IWineD3DDeviceImpl_InitGDI,
6856 IWineD3DDeviceImpl_Uninit3D,
6857 IWineD3DDeviceImpl_UninitGDI,
6858 IWineD3DDeviceImpl_SetMultithreaded,
6859 IWineD3DDeviceImpl_EvictManagedResources,
6860 IWineD3DDeviceImpl_GetAvailableTextureMem,
6861 IWineD3DDeviceImpl_GetBackBuffer,
6862 IWineD3DDeviceImpl_GetCreationParameters,
6863 IWineD3DDeviceImpl_GetDeviceCaps,
6864 IWineD3DDeviceImpl_GetDirect3D,
6865 IWineD3DDeviceImpl_GetDisplayMode,
6866 IWineD3DDeviceImpl_SetDisplayMode,
6867 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6868 IWineD3DDeviceImpl_GetRasterStatus,
6869 IWineD3DDeviceImpl_GetSwapChain,
6870 IWineD3DDeviceImpl_Reset,
6871 IWineD3DDeviceImpl_SetDialogBoxMode,
6872 IWineD3DDeviceImpl_SetCursorProperties,
6873 IWineD3DDeviceImpl_SetCursorPosition,
6874 IWineD3DDeviceImpl_ShowCursor,
6875 /*** Getters and setters **/
6876 IWineD3DDeviceImpl_SetClipPlane,
6877 IWineD3DDeviceImpl_GetClipPlane,
6878 IWineD3DDeviceImpl_SetClipStatus,
6879 IWineD3DDeviceImpl_GetClipStatus,
6880 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6881 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6882 IWineD3DDeviceImpl_SetDepthStencilSurface,
6883 IWineD3DDeviceImpl_GetDepthStencilSurface,
6884 IWineD3DDeviceImpl_SetGammaRamp,
6885 IWineD3DDeviceImpl_GetGammaRamp,
6886 IWineD3DDeviceImpl_SetIndexBuffer,
6887 IWineD3DDeviceImpl_GetIndexBuffer,
6888 IWineD3DDeviceImpl_SetBaseVertexIndex,
6889 IWineD3DDeviceImpl_GetBaseVertexIndex,
6890 IWineD3DDeviceImpl_SetLight,
6891 IWineD3DDeviceImpl_GetLight,
6892 IWineD3DDeviceImpl_SetLightEnable,
6893 IWineD3DDeviceImpl_GetLightEnable,
6894 IWineD3DDeviceImpl_SetMaterial,
6895 IWineD3DDeviceImpl_GetMaterial,
6896 IWineD3DDeviceImpl_SetNPatchMode,
6897 IWineD3DDeviceImpl_GetNPatchMode,
6898 IWineD3DDeviceImpl_SetPaletteEntries,
6899 IWineD3DDeviceImpl_GetPaletteEntries,
6900 IWineD3DDeviceImpl_SetPixelShader,
6901 IWineD3DDeviceImpl_GetPixelShader,
6902 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6903 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6904 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6905 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6906 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6907 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6908 IWineD3DDeviceImpl_SetRenderState,
6909 IWineD3DDeviceImpl_GetRenderState,
6910 IWineD3DDeviceImpl_SetRenderTarget,
6911 IWineD3DDeviceImpl_GetRenderTarget,
6912 IWineD3DDeviceImpl_SetFrontBackBuffers,
6913 IWineD3DDeviceImpl_SetSamplerState,
6914 IWineD3DDeviceImpl_GetSamplerState,
6915 IWineD3DDeviceImpl_SetScissorRect,
6916 IWineD3DDeviceImpl_GetScissorRect,
6917 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6918 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6919 IWineD3DDeviceImpl_SetStreamSource,
6920 IWineD3DDeviceImpl_GetStreamSource,
6921 IWineD3DDeviceImpl_SetStreamSourceFreq,
6922 IWineD3DDeviceImpl_GetStreamSourceFreq,
6923 IWineD3DDeviceImpl_SetTexture,
6924 IWineD3DDeviceImpl_GetTexture,
6925 IWineD3DDeviceImpl_SetTextureStageState,
6926 IWineD3DDeviceImpl_GetTextureStageState,
6927 IWineD3DDeviceImpl_SetTransform,
6928 IWineD3DDeviceImpl_GetTransform,
6929 IWineD3DDeviceImpl_SetVertexDeclaration,
6930 IWineD3DDeviceImpl_GetVertexDeclaration,
6931 IWineD3DDeviceImpl_SetVertexShader,
6932 IWineD3DDeviceImpl_GetVertexShader,
6933 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6934 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6935 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6936 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6937 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6938 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6939 IWineD3DDeviceImpl_SetViewport,
6940 IWineD3DDeviceImpl_GetViewport,
6941 IWineD3DDeviceImpl_MultiplyTransform,
6942 IWineD3DDeviceImpl_ValidateDevice,
6943 IWineD3DDeviceImpl_ProcessVertices,
6944 /*** State block ***/
6945 IWineD3DDeviceImpl_BeginStateBlock,
6946 IWineD3DDeviceImpl_EndStateBlock,
6947 /*** Scene management ***/
6948 IWineD3DDeviceImpl_BeginScene,
6949 IWineD3DDeviceImpl_EndScene,
6950 IWineD3DDeviceImpl_Present,
6951 IWineD3DDeviceImpl_Clear,
6952 IWineD3DDeviceImpl_ClearRendertargetView,
6954 IWineD3DDeviceImpl_SetPrimitiveType,
6955 IWineD3DDeviceImpl_GetPrimitiveType,
6956 IWineD3DDeviceImpl_DrawPrimitive,
6957 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6958 IWineD3DDeviceImpl_DrawPrimitiveUP,
6959 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6960 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6961 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6962 IWineD3DDeviceImpl_DrawRectPatch,
6963 IWineD3DDeviceImpl_DrawTriPatch,
6964 IWineD3DDeviceImpl_DeletePatch,
6965 IWineD3DDeviceImpl_ColorFill,
6966 IWineD3DDeviceImpl_UpdateTexture,
6967 IWineD3DDeviceImpl_UpdateSurface,
6968 IWineD3DDeviceImpl_GetFrontBufferData,
6969 /*** object tracking ***/
6970 IWineD3DDeviceImpl_EnumResources,
6971 IWineD3DDeviceImpl_GetSurfaceFromDC,
6972 IWineD3DDeviceImpl_AcquireFocusWindow,
6973 IWineD3DDeviceImpl_ReleaseFocusWindow,
6976 HRESULT device_init(IWineD3DDeviceImpl *device, IWineD3DImpl *wined3d,
6977 UINT adapter_idx, WINED3DDEVTYPE device_type, HWND focus_window, DWORD flags,
6978 IUnknown *parent, IWineD3DDeviceParent *device_parent)
6980 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
6981 const struct fragment_pipeline *fragment_pipeline;
6982 struct shader_caps shader_caps;
6983 struct fragment_caps ffp_caps;
6984 WINED3DDISPLAYMODE mode;
6988 device->lpVtbl = &IWineD3DDevice_Vtbl;
6990 device->wined3d = (IWineD3D *)wined3d;
6991 IWineD3D_AddRef(device->wined3d);
6992 device->adapter = wined3d->adapter_count ? adapter : NULL;
6993 device->parent = parent;
6994 device->device_parent = device_parent;
6995 list_init(&device->resources);
6996 list_init(&device->shaders);
6998 device->surface_alignment = wined3d->dxVersion == 7 ? DDRAW_PITCH_ALIGNMENT : D3D8_PITCH_ALIGNMENT;
6999 device->posFixup[0] = 1.0f; /* This is needed to get the x coord unmodified through a MAD. */
7001 /* Get the initial screen setup for ddraw. */
7002 hr = IWineD3D_GetAdapterDisplayMode((IWineD3D *)wined3d, adapter_idx, &mode);
7005 ERR("Failed to get the adapter's display mode, hr %#x.\n", hr);
7006 IWineD3D_Release(device->wined3d);
7009 device->ddraw_width = mode.Width;
7010 device->ddraw_height = mode.Height;
7011 device->ddraw_format = mode.Format;
7013 /* Save the creation parameters. */
7014 device->createParms.AdapterOrdinal = adapter_idx;
7015 device->createParms.DeviceType = device_type;
7016 device->createParms.hFocusWindow = focus_window;
7017 device->createParms.BehaviorFlags = flags;
7019 device->devType = device_type;
7020 for (i = 0; i < PATCHMAP_SIZE; ++i) list_init(&device->patches[i]);
7022 select_shader_mode(&adapter->gl_info, &device->ps_selected_mode, &device->vs_selected_mode);
7023 device->shader_backend = adapter->shader_backend;
7025 if (device->shader_backend)
7027 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
7028 device->d3d_vshader_constantF = shader_caps.MaxVertexShaderConst;
7029 device->d3d_pshader_constantF = shader_caps.MaxPixelShaderConst;
7030 device->vs_clipping = shader_caps.VSClipping;
7032 fragment_pipeline = adapter->fragment_pipe;
7033 device->frag_pipe = fragment_pipeline;
7034 if (fragment_pipeline)
7036 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
7037 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
7039 hr = compile_state_table(device->StateTable, device->multistate_funcs, &adapter->gl_info,
7040 ffp_vertexstate_template, fragment_pipeline, misc_state_template);
7043 ERR("Failed to compile state table, hr %#x.\n", hr);
7044 IWineD3D_Release(device->wined3d);
7048 device->blitter = adapter->blitter;
7054 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7055 DWORD rep = This->StateTable[state].representative;
7056 struct wined3d_context *context;
7061 for(i = 0; i < This->numContexts; i++) {
7062 context = This->contexts[i];
7063 if(isStateDirty(context, rep)) continue;
7065 context->dirtyArray[context->numDirtyEntries++] = rep;
7066 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
7067 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
7068 context->isStateDirty[idx] |= (1 << shift);
7072 void get_drawable_size_fbo(struct wined3d_context *context, UINT *width, UINT *height)
7074 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
7075 *width = context->current_rt->pow2Width;
7076 *height = context->current_rt->pow2Height;
7079 void get_drawable_size_backbuffer(struct wined3d_context *context, UINT *width, UINT *height)
7081 IWineD3DSwapChainImpl *swapchain = context->swapchain;
7082 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7083 * current context's drawable, which is the size of the back buffer of the swapchain
7084 * the active context belongs to. */
7085 *width = swapchain->presentParms.BackBufferWidth;
7086 *height = swapchain->presentParms.BackBufferHeight;
7089 LRESULT device_process_message(IWineD3DDeviceImpl *device, HWND window,
7090 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
7092 if (device->filter_messages)
7094 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
7095 window, message, wparam, lparam);
7096 return DefWindowProcW(window, message, wparam, lparam);
7099 if (message == WM_DESTROY)
7101 TRACE("unregister window %p.\n", window);
7102 wined3d_unregister_window(window);
7104 if (device->focus_window == window) device->focus_window = NULL;
7105 else ERR("Window %p is not the focus window for device %p.\n", window, device);
7108 return CallWindowProcW(proc, window, message, wparam, lparam);