2 * Copyright 2002 Lionel Ulmer
3 * Copyright 2002-2005 Jason Edmeades
4 * Copyright 2003-2004 Raphael Junqueira
5 * Copyright 2004 Christian Costa
6 * Copyright 2005 Oliver Stieber
7 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
8 * Copyright 2006-2008 Henri Verbeet
9 * Copyright 2007 Andrew Riedi
10 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
35 #include "wined3d_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
38 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
40 /* Define the default light parameters as specified by MSDN. */
41 const struct wined3d_light WINED3D_default_light =
43 WINED3D_LIGHT_DIRECTIONAL, /* Type */
44 { 1.0f, 1.0f, 1.0f, 0.0f }, /* Diffuse r,g,b,a */
45 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Specular r,g,b,a */
46 { 0.0f, 0.0f, 0.0f, 0.0f }, /* Ambient r,g,b,a, */
47 { 0.0f, 0.0f, 0.0f }, /* Position x,y,z */
48 { 0.0f, 0.0f, 1.0f }, /* Direction x,y,z */
51 0.0f, 0.0f, 0.0f, /* Attenuation 0,1,2 */
56 /**********************************************************
57 * Global variable / Constants follow
58 **********************************************************/
59 const struct wined3d_matrix identity =
61 1.0f, 0.0f, 0.0f, 0.0f,
62 0.0f, 1.0f, 0.0f, 0.0f,
63 0.0f, 0.0f, 1.0f, 0.0f,
64 0.0f, 0.0f, 0.0f, 1.0f,
65 }}}; /* When needed for comparisons */
67 /* Note that except for WINED3DPT_POINTLIST and WINED3DPT_LINELIST these
68 * actually have the same values in GL and D3D. */
69 GLenum gl_primitive_type_from_d3d(enum wined3d_primitive_type primitive_type)
71 switch(primitive_type)
73 case WINED3D_PT_POINTLIST:
76 case WINED3D_PT_LINELIST:
79 case WINED3D_PT_LINESTRIP:
82 case WINED3D_PT_TRIANGLELIST:
85 case WINED3D_PT_TRIANGLESTRIP:
86 return GL_TRIANGLE_STRIP;
88 case WINED3D_PT_TRIANGLEFAN:
89 return GL_TRIANGLE_FAN;
91 case WINED3D_PT_LINELIST_ADJ:
92 return GL_LINES_ADJACENCY_ARB;
94 case WINED3D_PT_LINESTRIP_ADJ:
95 return GL_LINE_STRIP_ADJACENCY_ARB;
97 case WINED3D_PT_TRIANGLELIST_ADJ:
98 return GL_TRIANGLES_ADJACENCY_ARB;
100 case WINED3D_PT_TRIANGLESTRIP_ADJ:
101 return GL_TRIANGLE_STRIP_ADJACENCY_ARB;
104 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
109 static enum wined3d_primitive_type d3d_primitive_type_from_gl(GLenum primitive_type)
111 switch(primitive_type)
114 return WINED3D_PT_POINTLIST;
117 return WINED3D_PT_LINELIST;
120 return WINED3D_PT_LINESTRIP;
123 return WINED3D_PT_TRIANGLELIST;
125 case GL_TRIANGLE_STRIP:
126 return WINED3D_PT_TRIANGLESTRIP;
128 case GL_TRIANGLE_FAN:
129 return WINED3D_PT_TRIANGLEFAN;
131 case GL_LINES_ADJACENCY_ARB:
132 return WINED3D_PT_LINELIST_ADJ;
134 case GL_LINE_STRIP_ADJACENCY_ARB:
135 return WINED3D_PT_LINESTRIP_ADJ;
137 case GL_TRIANGLES_ADJACENCY_ARB:
138 return WINED3D_PT_TRIANGLELIST_ADJ;
140 case GL_TRIANGLE_STRIP_ADJACENCY_ARB:
141 return WINED3D_PT_TRIANGLESTRIP_ADJ;
144 FIXME("Unhandled primitive type %s\n", debug_d3dprimitivetype(primitive_type));
145 return WINED3D_PT_UNDEFINED;
149 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
151 if ((usage == WINED3D_DECL_USAGE_POSITION || usage == WINED3D_DECL_USAGE_POSITIONT) && !usage_idx)
152 *regnum = WINED3D_FFP_POSITION;
153 else if (usage == WINED3D_DECL_USAGE_BLEND_WEIGHT && !usage_idx)
154 *regnum = WINED3D_FFP_BLENDWEIGHT;
155 else if (usage == WINED3D_DECL_USAGE_BLEND_INDICES && !usage_idx)
156 *regnum = WINED3D_FFP_BLENDINDICES;
157 else if (usage == WINED3D_DECL_USAGE_NORMAL && !usage_idx)
158 *regnum = WINED3D_FFP_NORMAL;
159 else if (usage == WINED3D_DECL_USAGE_PSIZE && !usage_idx)
160 *regnum = WINED3D_FFP_PSIZE;
161 else if (usage == WINED3D_DECL_USAGE_COLOR && !usage_idx)
162 *regnum = WINED3D_FFP_DIFFUSE;
163 else if (usage == WINED3D_DECL_USAGE_COLOR && usage_idx == 1)
164 *regnum = WINED3D_FFP_SPECULAR;
165 else if (usage == WINED3D_DECL_USAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
166 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
169 FIXME("Unsupported input stream [usage=%s, usage_idx=%u]\n", debug_d3ddeclusage(usage), usage_idx);
177 /* Context activation is done by the caller. */
178 static void device_stream_info_from_declaration(struct wined3d_device *device, struct wined3d_stream_info *stream_info)
180 const struct wined3d_state *state = &device->stateBlock->state;
181 /* We need to deal with frequency data! */
182 struct wined3d_vertex_declaration *declaration = state->vertex_declaration;
187 stream_info->use_map = 0;
188 stream_info->swizzle_map = 0;
189 stream_info->all_vbo = 1;
191 /* Check for transformed vertices, disable vertex shader if present. */
192 stream_info->position_transformed = declaration->position_transformed;
193 use_vshader = state->vertex_shader && !declaration->position_transformed;
195 /* Translate the declaration into strided data. */
196 for (i = 0; i < declaration->element_count; ++i)
198 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
199 const struct wined3d_stream_state *stream = &state->streams[element->input_slot];
200 struct wined3d_buffer *buffer = stream->buffer;
201 struct wined3d_bo_address data;
206 TRACE("%p Element %p (%u of %u)\n", declaration->elements,
207 element, i + 1, declaration->element_count);
209 if (!buffer) continue;
211 stride = stream->stride;
213 TRACE("Stream %u, buffer %p.\n", element->input_slot, buffer);
214 buffer_get_memory(buffer, &device->adapter->gl_info, &data);
216 /* We can't use VBOs if the base vertex index is negative. OpenGL
217 * doesn't accept negative offsets (or rather offsets bigger than the
218 * VBO, because the pointer is unsigned), so use system memory
219 * sources. In most sane cases the pointer - offset will still be > 0,
220 * otherwise it will wrap around to some big value. Hope that with the
221 * indices, the driver wraps it back internally. If not,
222 * drawStridedSlow() is needed, including a vertex buffer path. */
223 if (state->load_base_vertex_index < 0)
225 WARN_(d3d_perf)("load_base_vertex_index is < 0 (%d), not using VBOs.\n", state->load_base_vertex_index);
226 data.buffer_object = 0;
227 data.addr = buffer_get_sysmem(buffer, &device->adapter->gl_info);
228 if ((UINT_PTR)data.addr < -state->load_base_vertex_index * stride)
229 FIXME("System memory vertex data load offset is negative!\n");
231 data.addr += element->offset;
233 TRACE("offset %u input_slot %u usage_idx %d\n", element->offset, element->input_slot, element->usage_idx);
237 if (element->output_slot == ~0U)
239 /* TODO: Assuming vertexdeclarations are usually used with the
240 * same or a similar shader, it might be worth it to store the
241 * last used output slot and try that one first. */
242 stride_used = vshader_get_input(state->vertex_shader,
243 element->usage, element->usage_idx, &idx);
247 idx = element->output_slot;
253 if (!element->ffp_valid)
255 WARN("Skipping unsupported fixed function element of format %s and usage %s\n",
256 debug_d3dformat(element->format->id), debug_d3ddeclusage(element->usage));
261 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
267 TRACE("Load %s array %u [usage %s, usage_idx %u, "
268 "input_slot %u, offset %u, stride %u, format %s, buffer_object %u]\n",
269 use_vshader ? "shader": "fixed function", idx,
270 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
271 element->offset, stride, debug_d3dformat(element->format->id), data.buffer_object);
273 data.addr += stream->offset;
275 stream_info->elements[idx].format = element->format;
276 stream_info->elements[idx].data = data;
277 stream_info->elements[idx].stride = stride;
278 stream_info->elements[idx].stream_idx = element->input_slot;
280 if (!device->adapter->gl_info.supported[ARB_VERTEX_ARRAY_BGRA]
281 && element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
283 stream_info->swizzle_map |= 1 << idx;
285 stream_info->use_map |= 1 << idx;
289 /* Preload the vertex buffers. */
290 device->num_buffer_queries = 0;
291 for (i = 0, map = stream_info->use_map; map; map >>= 1, ++i)
293 struct wined3d_stream_info_element *element;
294 struct wined3d_buffer *buffer;
299 element = &stream_info->elements[i];
300 buffer = state->streams[element->stream_idx].buffer;
301 wined3d_buffer_preload(buffer);
303 /* If the preload dropped the buffer object, update the stream info. */
304 if (buffer->buffer_object != element->data.buffer_object)
306 element->data.buffer_object = 0;
307 element->data.addr = buffer_get_sysmem(buffer, &device->adapter->gl_info) + (ptrdiff_t)element->data.addr;
310 if (!buffer->buffer_object)
311 stream_info->all_vbo = 0;
314 device->buffer_queries[device->num_buffer_queries++] = buffer->query;
318 /* Context activation is done by the caller. */
319 void device_update_stream_info(struct wined3d_device *device, const struct wined3d_gl_info *gl_info)
321 struct wined3d_stream_info *stream_info = &device->stream_info;
322 const struct wined3d_state *state = &device->stateBlock->state;
323 DWORD prev_all_vbo = stream_info->all_vbo;
325 TRACE("============================= Vertex Declaration =============================\n");
326 device_stream_info_from_declaration(device, stream_info);
328 if (state->vertex_shader && !stream_info->position_transformed)
330 if (state->vertex_declaration->half_float_conv_needed && !stream_info->all_vbo)
332 TRACE("Using drawStridedSlow with vertex shaders for FLOAT16 conversion.\n");
333 device->useDrawStridedSlow = TRUE;
337 device->useDrawStridedSlow = FALSE;
342 WORD slow_mask = (1 << WINED3D_FFP_PSIZE);
343 slow_mask |= -!gl_info->supported[ARB_VERTEX_ARRAY_BGRA]
344 & ((1 << WINED3D_FFP_DIFFUSE) | (1 << WINED3D_FFP_SPECULAR));
346 if ((stream_info->position_transformed || (stream_info->use_map & slow_mask)) && !stream_info->all_vbo)
348 device->useDrawStridedSlow = TRUE;
352 device->useDrawStridedSlow = FALSE;
356 if (prev_all_vbo != stream_info->all_vbo)
357 device_invalidate_state(device, STATE_INDEXBUFFER);
360 static void device_preload_texture(const struct wined3d_state *state, unsigned int idx)
362 struct wined3d_texture *texture;
363 enum WINED3DSRGB srgb;
365 if (!(texture = state->textures[idx])) return;
366 srgb = state->sampler_states[idx][WINED3D_SAMP_SRGB_TEXTURE] ? SRGB_SRGB : SRGB_RGB;
367 texture->texture_ops->texture_preload(texture, srgb);
370 void device_preload_textures(const struct wined3d_device *device)
372 const struct wined3d_state *state = &device->stateBlock->state;
377 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i)
379 if (state->vertex_shader->reg_maps.sampler_type[i])
380 device_preload_texture(state, MAX_FRAGMENT_SAMPLERS + i);
386 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
388 if (state->pixel_shader->reg_maps.sampler_type[i])
389 device_preload_texture(state, i);
394 WORD ffu_map = device->fixed_function_usage_map;
396 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
399 device_preload_texture(state, i);
404 BOOL device_context_add(struct wined3d_device *device, struct wined3d_context *context)
406 struct wined3d_context **new_array;
408 TRACE("Adding context %p.\n", context);
410 if (!device->contexts) new_array = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_array));
411 else new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts,
412 sizeof(*new_array) * (device->context_count + 1));
416 ERR("Failed to grow the context array.\n");
420 new_array[device->context_count++] = context;
421 device->contexts = new_array;
425 void device_context_remove(struct wined3d_device *device, struct wined3d_context *context)
427 struct wined3d_context **new_array;
431 TRACE("Removing context %p.\n", context);
433 for (i = 0; i < device->context_count; ++i)
435 if (device->contexts[i] == context)
444 ERR("Context %p doesn't exist in context array.\n", context);
448 if (!--device->context_count)
450 HeapFree(GetProcessHeap(), 0, device->contexts);
451 device->contexts = NULL;
455 memmove(&device->contexts[i], &device->contexts[i + 1], (device->context_count - i) * sizeof(*device->contexts));
456 new_array = HeapReAlloc(GetProcessHeap(), 0, device->contexts, device->context_count * sizeof(*device->contexts));
459 ERR("Failed to shrink context array. Oh well.\n");
463 device->contexts = new_array;
466 /* Do not call while under the GL lock. */
467 void device_switch_onscreen_ds(struct wined3d_device *device,
468 struct wined3d_context *context, struct wined3d_surface *depth_stencil)
470 if (device->onscreen_depth_stencil)
472 surface_load_ds_location(device->onscreen_depth_stencil, context, SFLAG_INTEXTURE);
474 surface_modify_ds_location(device->onscreen_depth_stencil, SFLAG_INTEXTURE,
475 device->onscreen_depth_stencil->ds_current_size.cx,
476 device->onscreen_depth_stencil->ds_current_size.cy);
477 wined3d_surface_decref(device->onscreen_depth_stencil);
479 device->onscreen_depth_stencil = depth_stencil;
480 wined3d_surface_incref(device->onscreen_depth_stencil);
483 static BOOL is_full_clear(const struct wined3d_surface *target, const RECT *draw_rect, const RECT *clear_rect)
485 /* partial draw rect */
486 if (draw_rect->left || draw_rect->top
487 || draw_rect->right < target->resource.width
488 || draw_rect->bottom < target->resource.height)
491 /* partial clear rect */
492 if (clear_rect && (clear_rect->left > 0 || clear_rect->top > 0
493 || clear_rect->right < target->resource.width
494 || clear_rect->bottom < target->resource.height))
500 static void prepare_ds_clear(struct wined3d_surface *ds, struct wined3d_context *context,
501 DWORD location, const RECT *draw_rect, UINT rect_count, const RECT *clear_rect, RECT *out_rect)
503 RECT current_rect, r;
505 if (ds->flags & SFLAG_DISCARDED)
507 /* Depth buffer was discarded, make it entirely current in its new location since
508 * there is no other place where we would get data anyway. */
509 SetRect(out_rect, 0, 0, ds->resource.width, ds->resource.height);
513 if (ds->flags & location)
514 SetRect(¤t_rect, 0, 0,
515 ds->ds_current_size.cx,
516 ds->ds_current_size.cy);
518 SetRectEmpty(¤t_rect);
520 IntersectRect(&r, draw_rect, ¤t_rect);
521 if (EqualRect(&r, draw_rect))
523 /* current_rect ⊇ draw_rect, modify only. */
524 SetRect(out_rect, 0, 0, ds->ds_current_size.cx, ds->ds_current_size.cy);
528 if (EqualRect(&r, ¤t_rect))
530 /* draw_rect ⊇ current_rect, test if we're doing a full clear. */
534 /* Full clear, modify only. */
535 *out_rect = *draw_rect;
539 IntersectRect(&r, draw_rect, clear_rect);
540 if (EqualRect(&r, draw_rect))
542 /* clear_rect ⊇ draw_rect, modify only. */
543 *out_rect = *draw_rect;
549 surface_load_ds_location(ds, context, location);
550 SetRect(out_rect, 0, 0, ds->ds_current_size.cx, ds->ds_current_size.cy);
553 /* Do not call while under the GL lock. */
554 void device_clear_render_targets(struct wined3d_device *device, UINT rt_count, const struct wined3d_fb_state *fb,
555 UINT rect_count, const RECT *rects, const RECT *draw_rect, DWORD flags, const struct wined3d_color *color,
556 float depth, DWORD stencil)
558 const RECT *clear_rect = (rect_count > 0 && rects) ? (const RECT *)rects : NULL;
559 struct wined3d_surface *target = rt_count ? fb->render_targets[0] : NULL;
560 const struct wined3d_gl_info *gl_info;
561 UINT drawable_width, drawable_height;
562 struct wined3d_context *context;
563 GLbitfield clear_mask = 0;
564 BOOL render_offscreen;
568 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
569 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
570 * for the cleared parts, and the untouched parts.
572 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
573 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
574 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
575 * checking all this if the dest surface is in the drawable anyway. */
576 if (flags & WINED3DCLEAR_TARGET && !is_full_clear(target, draw_rect, clear_rect))
578 for (i = 0; i < rt_count; ++i)
580 struct wined3d_surface *rt = fb->render_targets[i];
582 surface_load_location(rt, rt->draw_binding, NULL);
586 context = context_acquire(device, target);
589 context_release(context);
590 WARN("Invalid context, skipping clear.\n");
593 gl_info = context->gl_info;
597 render_offscreen = context->render_offscreen;
598 target->get_drawable_size(context, &drawable_width, &drawable_height);
602 render_offscreen = TRUE;
603 drawable_width = fb->depth_stencil->pow2Width;
604 drawable_height = fb->depth_stencil->pow2Height;
607 if (flags & WINED3DCLEAR_ZBUFFER)
609 DWORD location = render_offscreen ? fb->depth_stencil->draw_binding : SFLAG_INDRAWABLE;
611 if (!render_offscreen && fb->depth_stencil != device->onscreen_depth_stencil)
612 device_switch_onscreen_ds(device, context, fb->depth_stencil);
613 prepare_ds_clear(fb->depth_stencil, context, location,
614 draw_rect, rect_count, clear_rect, &ds_rect);
617 if (!context_apply_clear_state(context, device, rt_count, fb))
619 context_release(context);
620 WARN("Failed to apply clear state, skipping clear.\n");
624 /* Only set the values up once, as they are not changing. */
625 if (flags & WINED3DCLEAR_STENCIL)
627 if (gl_info->supported[EXT_STENCIL_TWO_SIDE])
629 gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
630 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
632 gl_info->gl_ops.gl.p_glStencilMask(~0U);
633 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
634 gl_info->gl_ops.gl.p_glClearStencil(stencil);
635 checkGLcall("glClearStencil");
636 clear_mask = clear_mask | GL_STENCIL_BUFFER_BIT;
639 if (flags & WINED3DCLEAR_ZBUFFER)
641 DWORD location = render_offscreen ? fb->depth_stencil->draw_binding : SFLAG_INDRAWABLE;
643 surface_modify_ds_location(fb->depth_stencil, location, ds_rect.right, ds_rect.bottom);
645 gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
646 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
647 gl_info->gl_ops.gl.p_glClearDepth(depth);
648 checkGLcall("glClearDepth");
649 clear_mask = clear_mask | GL_DEPTH_BUFFER_BIT;
652 if (flags & WINED3DCLEAR_TARGET)
654 for (i = 0; i < rt_count; ++i)
656 struct wined3d_surface *rt = fb->render_targets[i];
659 surface_modify_location(rt, rt->draw_binding, TRUE);
662 gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
663 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE));
664 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE1));
665 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE2));
666 context_invalidate_state(context, STATE_RENDER(WINED3D_RS_COLORWRITEENABLE3));
667 gl_info->gl_ops.gl.p_glClearColor(color->r, color->g, color->b, color->a);
668 checkGLcall("glClearColor");
669 clear_mask = clear_mask | GL_COLOR_BUFFER_BIT;
674 if (render_offscreen)
676 gl_info->gl_ops.gl.p_glScissor(draw_rect->left, draw_rect->top,
677 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
681 gl_info->gl_ops.gl.p_glScissor(draw_rect->left, drawable_height - draw_rect->bottom,
682 draw_rect->right - draw_rect->left, draw_rect->bottom - draw_rect->top);
684 checkGLcall("glScissor");
685 gl_info->gl_ops.gl.p_glClear(clear_mask);
686 checkGLcall("glClear");
692 /* Now process each rect in turn. */
693 for (i = 0; i < rect_count; ++i)
695 /* Note that GL uses lower left, width/height. */
696 IntersectRect(¤t_rect, draw_rect, &clear_rect[i]);
698 TRACE("clear_rect[%u] %s, current_rect %s.\n", i,
699 wine_dbgstr_rect(&clear_rect[i]),
700 wine_dbgstr_rect(¤t_rect));
702 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
703 * The rectangle is not cleared, no error is returned, but further rectangles are
704 * still cleared if they are valid. */
705 if (current_rect.left > current_rect.right || current_rect.top > current_rect.bottom)
707 TRACE("Rectangle with negative dimensions, ignoring.\n");
711 if (render_offscreen)
713 gl_info->gl_ops.gl.p_glScissor(current_rect.left, current_rect.top,
714 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
718 gl_info->gl_ops.gl.p_glScissor(current_rect.left, drawable_height - current_rect.bottom,
719 current_rect.right - current_rect.left, current_rect.bottom - current_rect.top);
721 checkGLcall("glScissor");
723 gl_info->gl_ops.gl.p_glClear(clear_mask);
724 checkGLcall("glClear");
728 if (wined3d_settings.strict_draw_ordering || (flags & WINED3DCLEAR_TARGET
729 && target->container.type == WINED3D_CONTAINER_SWAPCHAIN
730 && target->container.u.swapchain->front_buffer == target))
731 gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
733 context_release(context);
736 ULONG CDECL wined3d_device_incref(struct wined3d_device *device)
738 ULONG refcount = InterlockedIncrement(&device->ref);
740 TRACE("%p increasing refcount to %u.\n", device, refcount);
745 ULONG CDECL wined3d_device_decref(struct wined3d_device *device)
747 ULONG refcount = InterlockedDecrement(&device->ref);
749 TRACE("%p decreasing refcount to %u.\n", device, refcount);
753 struct wined3d_stateblock *stateblock;
756 if (wined3d_stateblock_decref(device->updateStateBlock)
757 && device->updateStateBlock != device->stateBlock)
758 FIXME("Something's still holding the update stateblock.\n");
759 device->updateStateBlock = NULL;
761 stateblock = device->stateBlock;
762 device->stateBlock = NULL;
763 if (wined3d_stateblock_decref(stateblock))
764 FIXME("Something's still holding the stateblock.\n");
766 for (i = 0; i < sizeof(device->multistate_funcs) / sizeof(device->multistate_funcs[0]); ++i)
768 HeapFree(GetProcessHeap(), 0, device->multistate_funcs[i]);
769 device->multistate_funcs[i] = NULL;
772 if (!list_empty(&device->resources))
774 struct wined3d_resource *resource;
776 FIXME("Device released with resources still bound, acceptable but unexpected.\n");
778 LIST_FOR_EACH_ENTRY(resource, &device->resources, struct wined3d_resource, resource_list_entry)
780 FIXME("Leftover resource %p with type %s (%#x).\n",
781 resource, debug_d3dresourcetype(resource->type), resource->type);
785 if (device->contexts)
786 ERR("Context array not freed!\n");
787 if (device->hardwareCursor)
788 DestroyCursor(device->hardwareCursor);
789 device->hardwareCursor = 0;
791 wined3d_decref(device->wined3d);
792 device->wined3d = NULL;
793 HeapFree(GetProcessHeap(), 0, device);
794 TRACE("Freed device %p.\n", device);
800 UINT CDECL wined3d_device_get_swapchain_count(const struct wined3d_device *device)
802 TRACE("device %p.\n", device);
804 return device->swapchain_count;
807 struct wined3d_swapchain * CDECL wined3d_device_get_swapchain(const struct wined3d_device *device, UINT swapchain_idx)
809 TRACE("device %p, swapchain_idx %u.\n", device, swapchain_idx);
811 if (swapchain_idx >= device->swapchain_count)
813 WARN("swapchain_idx %u >= swapchain_count %u.\n",
814 swapchain_idx, device->swapchain_count);
818 return device->swapchains[swapchain_idx];
821 static void device_load_logo(struct wined3d_device *device, const char *filename)
823 struct wined3d_color_key color_key;
827 HDC dcb = NULL, dcs = NULL;
829 hbm = LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
832 GetObjectA(hbm, sizeof(BITMAP), &bm);
833 dcb = CreateCompatibleDC(NULL);
835 SelectObject(dcb, hbm);
839 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
842 memset(&bm, 0, sizeof(bm));
847 hr = wined3d_surface_create(device, bm.bmWidth, bm.bmHeight, WINED3DFMT_B5G6R5_UNORM, 0,
848 WINED3D_POOL_SYSTEM_MEM, WINED3D_MULTISAMPLE_NONE, 0, WINED3D_SURFACE_MAPPABLE,
849 NULL, &wined3d_null_parent_ops, &device->logo_surface);
852 ERR("Wine logo requested, but failed to create surface, hr %#x.\n", hr);
858 if (FAILED(hr = wined3d_surface_getdc(device->logo_surface, &dcs)))
860 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
861 wined3d_surface_releasedc(device->logo_surface, dcs);
863 color_key.color_space_low_value = 0;
864 color_key.color_space_high_value = 0;
865 wined3d_surface_set_color_key(device->logo_surface, WINEDDCKEY_SRCBLT, &color_key);
869 const struct wined3d_color c = {1.0f, 1.0f, 1.0f, 1.0f};
870 /* Fill the surface with a white color to show that wined3d is there */
871 wined3d_device_color_fill(device, device->logo_surface, NULL, &c);
875 if (dcb) DeleteDC(dcb);
876 if (hbm) DeleteObject(hbm);
879 /* Context activation is done by the caller. */
880 static void create_dummy_textures(struct wined3d_device *device, struct wined3d_context *context)
882 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
883 unsigned int i, j, count;
884 /* Under DirectX you can sample even if no texture is bound, whereas
885 * OpenGL will only allow that when a valid texture is bound.
886 * We emulate this by creating dummy textures and binding them
887 * to each texture stage when the currently set D3D texture is NULL. */
889 if (gl_info->supported[APPLE_CLIENT_STORAGE])
891 /* The dummy texture does not have client storage backing */
892 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
893 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
896 count = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers);
897 for (i = 0; i < count; ++i)
899 DWORD color = 0x000000ff;
901 /* Make appropriate texture active */
902 context_active_texture(context, gl_info, i);
904 gl_info->gl_ops.gl.p_glGenTextures(1, &device->dummy_texture_2d[i]);
905 checkGLcall("glGenTextures");
906 TRACE("Dummy 2D texture %u given name %u.\n", i, device->dummy_texture_2d[i]);
908 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_2D, device->dummy_texture_2d[i]);
909 checkGLcall("glBindTexture");
911 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0,
912 GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, &color);
913 checkGLcall("glTexImage2D");
915 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
917 gl_info->gl_ops.gl.p_glGenTextures(1, &device->dummy_texture_rect[i]);
918 checkGLcall("glGenTextures");
919 TRACE("Dummy rectangle texture %u given name %u.\n", i, device->dummy_texture_rect[i]);
921 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_RECTANGLE_ARB, device->dummy_texture_rect[i]);
922 checkGLcall("glBindTexture");
924 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, 1, 1, 0,
925 GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, &color);
926 checkGLcall("glTexImage2D");
929 if (gl_info->supported[EXT_TEXTURE3D])
931 gl_info->gl_ops.gl.p_glGenTextures(1, &device->dummy_texture_3d[i]);
932 checkGLcall("glGenTextures");
933 TRACE("Dummy 3D texture %u given name %u.\n", i, device->dummy_texture_3d[i]);
935 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_3D, device->dummy_texture_3d[i]);
936 checkGLcall("glBindTexture");
938 GL_EXTCALL(glTexImage3DEXT(GL_TEXTURE_3D, 0, GL_RGBA8, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, &color));
939 checkGLcall("glTexImage3D");
942 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
944 gl_info->gl_ops.gl.p_glGenTextures(1, &device->dummy_texture_cube[i]);
945 checkGLcall("glGenTextures");
946 TRACE("Dummy cube texture %u given name %u.\n", i, device->dummy_texture_cube[i]);
948 gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_CUBE_MAP, device->dummy_texture_cube[i]);
949 checkGLcall("glBindTexture");
951 for (j = GL_TEXTURE_CUBE_MAP_POSITIVE_X; j <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; ++j)
953 gl_info->gl_ops.gl.p_glTexImage2D(j, 0, GL_RGBA8, 1, 1, 0,
954 GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, &color);
955 checkGLcall("glTexImage2D");
960 if (gl_info->supported[APPLE_CLIENT_STORAGE])
962 /* Re-enable because if supported it is enabled by default */
963 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
964 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
968 /* Context activation is done by the caller. */
969 static void destroy_dummy_textures(struct wined3d_device *device, const struct wined3d_gl_info *gl_info)
971 unsigned int count = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers);
973 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
975 gl_info->gl_ops.gl.p_glDeleteTextures(count, device->dummy_texture_cube);
976 checkGLcall("glDeleteTextures(count, device->dummy_texture_cube)");
979 if (gl_info->supported[EXT_TEXTURE3D])
981 gl_info->gl_ops.gl.p_glDeleteTextures(count, device->dummy_texture_3d);
982 checkGLcall("glDeleteTextures(count, device->dummy_texture_3d)");
985 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
987 gl_info->gl_ops.gl.p_glDeleteTextures(count, device->dummy_texture_rect);
988 checkGLcall("glDeleteTextures(count, device->dummy_texture_rect)");
991 gl_info->gl_ops.gl.p_glDeleteTextures(count, device->dummy_texture_2d);
992 checkGLcall("glDeleteTextures(count, device->dummy_texture_2d)");
994 memset(device->dummy_texture_cube, 0, count * sizeof(*device->dummy_texture_cube));
995 memset(device->dummy_texture_3d, 0, count * sizeof(*device->dummy_texture_3d));
996 memset(device->dummy_texture_rect, 0, count * sizeof(*device->dummy_texture_rect));
997 memset(device->dummy_texture_2d, 0, count * sizeof(*device->dummy_texture_2d));
1000 static LONG fullscreen_style(LONG style)
1002 /* Make sure the window is managed, otherwise we won't get keyboard input. */
1003 style |= WS_POPUP | WS_SYSMENU;
1004 style &= ~(WS_CAPTION | WS_THICKFRAME);
1009 static LONG fullscreen_exstyle(LONG exstyle)
1011 /* Filter out window decorations. */
1012 exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
1017 void CDECL wined3d_device_setup_fullscreen_window(struct wined3d_device *device, HWND window, UINT w, UINT h)
1019 BOOL filter_messages;
1020 LONG style, exstyle;
1022 TRACE("Setting up window %p for fullscreen mode.\n", window);
1024 if (device->style || device->exStyle)
1026 ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
1027 window, device->style, device->exStyle);
1030 device->style = GetWindowLongW(window, GWL_STYLE);
1031 device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1033 style = fullscreen_style(device->style);
1034 exstyle = fullscreen_exstyle(device->exStyle);
1036 TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
1037 device->style, device->exStyle, style, exstyle);
1039 filter_messages = device->filter_messages;
1040 device->filter_messages = TRUE;
1042 SetWindowLongW(window, GWL_STYLE, style);
1043 SetWindowLongW(window, GWL_EXSTYLE, exstyle);
1044 SetWindowPos(window, HWND_TOPMOST, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
1046 device->filter_messages = filter_messages;
1049 void CDECL wined3d_device_restore_fullscreen_window(struct wined3d_device *device, HWND window)
1051 BOOL filter_messages;
1052 LONG style, exstyle;
1054 if (!device->style && !device->exStyle) return;
1056 style = GetWindowLongW(window, GWL_STYLE);
1057 exstyle = GetWindowLongW(window, GWL_EXSTYLE);
1059 /* These flags are set by wined3d_device_setup_fullscreen_window, not the
1060 * application, and we want to ignore them in the test below, since it's
1061 * not the application's fault that they changed. Additionally, we want to
1062 * preserve the current status of these flags (i.e. don't restore them) to
1063 * more closely emulate the behavior of Direct3D, which leaves these flags
1064 * alone when returning to windowed mode. */
1065 device->style ^= (device->style ^ style) & WS_VISIBLE;
1066 device->exStyle ^= (device->exStyle ^ exstyle) & WS_EX_TOPMOST;
1068 TRACE("Restoring window style of window %p to %08x, %08x.\n",
1069 window, device->style, device->exStyle);
1071 filter_messages = device->filter_messages;
1072 device->filter_messages = TRUE;
1074 /* Only restore the style if the application didn't modify it during the
1075 * fullscreen phase. Some applications change it before calling Reset()
1076 * when switching between windowed and fullscreen modes (HL2), some
1077 * depend on the original style (Eve Online). */
1078 if (style == fullscreen_style(device->style) && exstyle == fullscreen_exstyle(device->exStyle))
1080 SetWindowLongW(window, GWL_STYLE, device->style);
1081 SetWindowLongW(window, GWL_EXSTYLE, device->exStyle);
1083 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1085 device->filter_messages = filter_messages;
1087 /* Delete the old values. */
1089 device->exStyle = 0;
1092 HRESULT CDECL wined3d_device_acquire_focus_window(struct wined3d_device *device, HWND window)
1094 TRACE("device %p, window %p.\n", device, window);
1096 if (!wined3d_register_window(window, device))
1098 ERR("Failed to register window %p.\n", window);
1102 InterlockedExchangePointer((void **)&device->focus_window, window);
1103 SetWindowPos(window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1108 void CDECL wined3d_device_release_focus_window(struct wined3d_device *device)
1110 TRACE("device %p.\n", device);
1112 if (device->focus_window) wined3d_unregister_window(device->focus_window);
1113 InterlockedExchangePointer((void **)&device->focus_window, NULL);
1116 HRESULT CDECL wined3d_device_init_3d(struct wined3d_device *device,
1117 struct wined3d_swapchain_desc *swapchain_desc)
1119 static const struct wined3d_color black = {0.0f, 0.0f, 0.0f, 0.0f};
1120 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1121 struct wined3d_swapchain *swapchain = NULL;
1122 struct wined3d_context *context;
1127 TRACE("device %p, swapchain_desc %p.\n", device, swapchain_desc);
1129 if (device->d3d_initialized)
1130 return WINED3DERR_INVALIDCALL;
1131 if (device->wined3d->flags & WINED3D_NO3D)
1132 return WINED3DERR_INVALIDCALL;
1134 device->valid_rt_mask = 0;
1135 for (i = 0; i < gl_info->limits.buffers; ++i)
1136 device->valid_rt_mask |= (1 << i);
1137 device->fb.render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1138 sizeof(*device->fb.render_targets) * gl_info->limits.buffers);
1140 /* Initialize the texture unit mapping to a 1:1 mapping */
1141 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state)
1143 if (state < gl_info->limits.fragment_samplers)
1145 device->texUnitMap[state] = state;
1146 device->rev_tex_unit_map[state] = state;
1150 device->texUnitMap[state] = WINED3D_UNMAPPED_STAGE;
1151 device->rev_tex_unit_map[state] = WINED3D_UNMAPPED_STAGE;
1155 if (FAILED(hr = device->shader_backend->shader_alloc_private(device, device->adapter->fragment_pipe)))
1157 TRACE("Shader private data couldn't be allocated\n");
1160 if (FAILED(hr = device->blitter->alloc_private(device)))
1162 TRACE("Blitter private data couldn't be allocated\n");
1166 /* Setup the implicit swapchain. This also initializes a context. */
1167 TRACE("Creating implicit swapchain\n");
1168 hr = device->device_parent->ops->create_swapchain(device->device_parent,
1169 swapchain_desc, &swapchain);
1172 WARN("Failed to create implicit swapchain\n");
1176 device->swapchain_count = 1;
1177 device->swapchains = HeapAlloc(GetProcessHeap(), 0, device->swapchain_count * sizeof(*device->swapchains));
1178 if (!device->swapchains)
1180 ERR("Out of memory!\n");
1183 device->swapchains[0] = swapchain;
1185 if (swapchain->back_buffers && swapchain->back_buffers[0])
1187 TRACE("Setting rendertarget to %p.\n", swapchain->back_buffers);
1188 device->fb.render_targets[0] = swapchain->back_buffers[0];
1192 TRACE("Setting rendertarget to %p.\n", swapchain->front_buffer);
1193 device->fb.render_targets[0] = swapchain->front_buffer;
1195 wined3d_surface_incref(device->fb.render_targets[0]);
1197 /* Depth Stencil support */
1198 device->fb.depth_stencil = device->auto_depth_stencil;
1199 if (device->fb.depth_stencil)
1200 wined3d_surface_incref(device->fb.depth_stencil);
1202 /* Set up some starting GL setup */
1204 /* Setup all the devices defaults */
1205 stateblock_init_default_state(device->stateBlock);
1207 context = context_acquire(device, swapchain->front_buffer);
1209 create_dummy_textures(device, context);
1211 /* Initialize the current view state */
1212 device->view_ident = 1;
1213 device->contexts[0]->last_was_rhw = 0;
1215 switch (wined3d_settings.offscreen_rendering_mode)
1218 device->offscreenBuffer = GL_COLOR_ATTACHMENT0;
1221 case ORM_BACKBUFFER:
1223 if (context_get_current()->aux_buffers > 0)
1225 TRACE("Using auxiliary buffer for offscreen rendering\n");
1226 device->offscreenBuffer = GL_AUX0;
1230 TRACE("Using back buffer for offscreen rendering\n");
1231 device->offscreenBuffer = GL_BACK;
1236 TRACE("All defaults now set up, leaving 3D init.\n");
1238 context_release(context);
1240 /* Clear the screen */
1241 wined3d_device_clear(device, 0, NULL, WINED3DCLEAR_TARGET
1242 | (swapchain_desc->enable_auto_depth_stencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0),
1245 device->d3d_initialized = TRUE;
1247 if (wined3d_settings.logo)
1248 device_load_logo(device, wined3d_settings.logo);
1252 HeapFree(GetProcessHeap(), 0, device->fb.render_targets);
1253 HeapFree(GetProcessHeap(), 0, device->swapchains);
1254 device->swapchain_count = 0;
1256 wined3d_swapchain_decref(swapchain);
1257 if (device->blit_priv)
1258 device->blitter->free_private(device);
1259 if (device->shader_priv)
1260 device->shader_backend->shader_free_private(device);
1265 HRESULT CDECL wined3d_device_init_gdi(struct wined3d_device *device,
1266 struct wined3d_swapchain_desc *swapchain_desc)
1268 struct wined3d_swapchain *swapchain = NULL;
1271 TRACE("device %p, swapchain_desc %p.\n", device, swapchain_desc);
1273 /* Setup the implicit swapchain */
1274 TRACE("Creating implicit swapchain\n");
1275 hr = device->device_parent->ops->create_swapchain(device->device_parent,
1276 swapchain_desc, &swapchain);
1279 WARN("Failed to create implicit swapchain\n");
1283 device->swapchain_count = 1;
1284 device->swapchains = HeapAlloc(GetProcessHeap(), 0, device->swapchain_count * sizeof(*device->swapchains));
1285 if (!device->swapchains)
1287 ERR("Out of memory!\n");
1290 device->swapchains[0] = swapchain;
1294 wined3d_swapchain_decref(swapchain);
1298 HRESULT CDECL wined3d_device_uninit_3d(struct wined3d_device *device)
1300 struct wined3d_resource *resource, *cursor;
1301 const struct wined3d_gl_info *gl_info;
1302 struct wined3d_context *context;
1303 struct wined3d_surface *surface;
1306 TRACE("device %p.\n", device);
1308 if (!device->d3d_initialized)
1309 return WINED3DERR_INVALIDCALL;
1311 /* Force making the context current again, to verify it is still valid
1312 * (workaround for broken drivers) */
1313 context_set_current(NULL);
1314 /* I don't think that the interface guarantees that the device is destroyed from the same thread
1315 * it was created. Thus make sure a context is active for the glDelete* calls
1317 context = context_acquire(device, NULL);
1318 gl_info = context->gl_info;
1320 if (device->logo_surface)
1321 wined3d_surface_decref(device->logo_surface);
1323 stateblock_unbind_resources(device->stateBlock);
1325 /* Unload resources */
1326 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
1328 TRACE("Unloading resource %p.\n", resource);
1330 resource->resource_ops->resource_unload(resource);
1333 /* Delete the mouse cursor texture */
1334 if (device->cursorTexture)
1336 gl_info->gl_ops.gl.p_glDeleteTextures(1, &device->cursorTexture);
1337 device->cursorTexture = 0;
1340 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
1341 * private data, it might contain opengl pointers
1343 if (device->depth_blt_texture)
1345 gl_info->gl_ops.gl.p_glDeleteTextures(1, &device->depth_blt_texture);
1346 device->depth_blt_texture = 0;
1349 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
1350 device->blitter->free_private(device);
1351 device->shader_backend->shader_free_private(device);
1353 /* Release the buffers (with sanity checks)*/
1354 if (device->onscreen_depth_stencil)
1356 surface = device->onscreen_depth_stencil;
1357 device->onscreen_depth_stencil = NULL;
1358 wined3d_surface_decref(surface);
1361 if (device->fb.depth_stencil)
1363 surface = device->fb.depth_stencil;
1365 TRACE("Releasing depth/stencil buffer %p.\n", surface);
1367 device->fb.depth_stencil = NULL;
1368 wined3d_surface_decref(surface);
1371 if (device->auto_depth_stencil)
1373 surface = device->auto_depth_stencil;
1374 device->auto_depth_stencil = NULL;
1375 if (wined3d_surface_decref(surface))
1376 FIXME("Something's still holding the auto depth stencil buffer (%p).\n", surface);
1379 for (i = 1; i < gl_info->limits.buffers; ++i)
1381 wined3d_device_set_render_target(device, i, NULL, FALSE);
1384 surface = device->fb.render_targets[0];
1385 TRACE("Setting rendertarget 0 to NULL\n");
1386 device->fb.render_targets[0] = NULL;
1387 TRACE("Releasing the render target at %p\n", surface);
1388 wined3d_surface_decref(surface);
1390 context_release(context);
1392 for (i = 0; i < device->swapchain_count; ++i)
1394 TRACE("Releasing the implicit swapchain %u.\n", i);
1395 if (wined3d_swapchain_decref(device->swapchains[i]))
1396 FIXME("Something's still holding the implicit swapchain.\n");
1399 HeapFree(GetProcessHeap(), 0, device->swapchains);
1400 device->swapchains = NULL;
1401 device->swapchain_count = 0;
1403 HeapFree(GetProcessHeap(), 0, device->fb.render_targets);
1404 device->fb.render_targets = NULL;
1406 device->d3d_initialized = FALSE;
1411 HRESULT CDECL wined3d_device_uninit_gdi(struct wined3d_device *device)
1415 for (i = 0; i < device->swapchain_count; ++i)
1417 TRACE("Releasing the implicit swapchain %u.\n", i);
1418 if (wined3d_swapchain_decref(device->swapchains[i]))
1419 FIXME("Something's still holding the implicit swapchain.\n");
1422 HeapFree(GetProcessHeap(), 0, device->swapchains);
1423 device->swapchains = NULL;
1424 device->swapchain_count = 0;
1428 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
1429 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1430 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1432 * There is no way to deactivate thread safety once it is enabled.
1434 void CDECL wined3d_device_set_multithreaded(struct wined3d_device *device)
1436 TRACE("device %p.\n", device);
1438 /* For now just store the flag (needed in case of ddraw). */
1439 device->create_parms.flags |= WINED3DCREATE_MULTITHREADED;
1442 UINT CDECL wined3d_device_get_available_texture_mem(const struct wined3d_device *device)
1444 TRACE("device %p.\n", device);
1446 TRACE("Emulating %d MB, returning %d MB left.\n",
1447 device->adapter->TextureRam / (1024 * 1024),
1448 (device->adapter->TextureRam - device->adapter->UsedTextureRam) / (1024 * 1024));
1450 return device->adapter->TextureRam - device->adapter->UsedTextureRam;
1453 void CDECL wined3d_device_set_stream_output(struct wined3d_device *device, UINT idx,
1454 struct wined3d_buffer *buffer, UINT offset)
1456 struct wined3d_buffer *prev_buffer;
1458 TRACE("device %p, idx %u, buffer %p, offset %u.\n", device, idx, buffer, offset);
1460 if (idx >= MAX_STREAM_OUT)
1462 WARN("Invalid stream output %u.\n", idx);
1466 prev_buffer = device->updateStateBlock->state.stream_output[idx].buffer;
1467 device->updateStateBlock->state.stream_output[idx].buffer = buffer;
1468 device->updateStateBlock->state.stream_output[idx].offset = offset;
1470 if (device->isRecordingState)
1473 wined3d_buffer_incref(buffer);
1475 wined3d_buffer_decref(prev_buffer);
1479 if (prev_buffer != buffer)
1483 InterlockedIncrement(&buffer->resource.bind_count);
1484 wined3d_buffer_incref(buffer);
1488 InterlockedDecrement(&prev_buffer->resource.bind_count);
1489 wined3d_buffer_decref(prev_buffer);
1494 struct wined3d_buffer * CDECL wined3d_device_get_stream_output(struct wined3d_device *device,
1495 UINT idx, UINT *offset)
1497 TRACE("device %p, idx %u, offset %p.\n", device, idx, offset);
1499 if (idx >= MAX_STREAM_OUT)
1501 WARN("Invalid stream output %u.\n", idx);
1505 *offset = device->stateBlock->state.stream_output[idx].offset;
1506 return device->stateBlock->state.stream_output[idx].buffer;
1509 HRESULT CDECL wined3d_device_set_stream_source(struct wined3d_device *device, UINT stream_idx,
1510 struct wined3d_buffer *buffer, UINT offset, UINT stride)
1512 struct wined3d_stream_state *stream;
1513 struct wined3d_buffer *prev_buffer;
1515 TRACE("device %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
1516 device, stream_idx, buffer, offset, stride);
1518 if (stream_idx >= MAX_STREAMS)
1520 WARN("Stream index %u out of range.\n", stream_idx);
1521 return WINED3DERR_INVALIDCALL;
1523 else if (offset & 0x3)
1525 WARN("Offset %u is not 4 byte aligned.\n", offset);
1526 return WINED3DERR_INVALIDCALL;
1529 stream = &device->updateStateBlock->state.streams[stream_idx];
1530 prev_buffer = stream->buffer;
1532 device->updateStateBlock->changed.streamSource |= 1 << stream_idx;
1534 if (prev_buffer == buffer
1535 && stream->stride == stride
1536 && stream->offset == offset)
1538 TRACE("Application is setting the old values over, nothing to do.\n");
1542 stream->buffer = buffer;
1545 stream->stride = stride;
1546 stream->offset = offset;
1549 /* Handle recording of state blocks. */
1550 if (device->isRecordingState)
1552 TRACE("Recording... not performing anything.\n");
1554 wined3d_buffer_incref(buffer);
1556 wined3d_buffer_decref(prev_buffer);
1562 InterlockedIncrement(&buffer->resource.bind_count);
1563 wined3d_buffer_incref(buffer);
1567 InterlockedDecrement(&prev_buffer->resource.bind_count);
1568 wined3d_buffer_decref(prev_buffer);
1571 device_invalidate_state(device, STATE_STREAMSRC);
1576 HRESULT CDECL wined3d_device_get_stream_source(const struct wined3d_device *device,
1577 UINT stream_idx, struct wined3d_buffer **buffer, UINT *offset, UINT *stride)
1579 struct wined3d_stream_state *stream;
1581 TRACE("device %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
1582 device, stream_idx, buffer, offset, stride);
1584 if (stream_idx >= MAX_STREAMS)
1586 WARN("Stream index %u out of range.\n", stream_idx);
1587 return WINED3DERR_INVALIDCALL;
1590 stream = &device->stateBlock->state.streams[stream_idx];
1591 *buffer = stream->buffer;
1593 wined3d_buffer_incref(*buffer);
1595 *offset = stream->offset;
1596 *stride = stream->stride;
1601 HRESULT CDECL wined3d_device_set_stream_source_freq(struct wined3d_device *device, UINT stream_idx, UINT divider)
1603 struct wined3d_stream_state *stream;
1604 UINT old_flags, old_freq;
1606 TRACE("device %p, stream_idx %u, divider %#x.\n", device, stream_idx, divider);
1608 /* Verify input. At least in d3d9 this is invalid. */
1609 if ((divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (divider & WINED3DSTREAMSOURCE_INDEXEDDATA))
1611 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL.\n");
1612 return WINED3DERR_INVALIDCALL;
1614 if ((divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && !stream_idx)
1616 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL.\n");
1617 return WINED3DERR_INVALIDCALL;
1621 WARN("Divider is 0, returning D3DERR_INVALIDCALL.\n");
1622 return WINED3DERR_INVALIDCALL;
1625 stream = &device->updateStateBlock->state.streams[stream_idx];
1626 old_flags = stream->flags;
1627 old_freq = stream->frequency;
1629 stream->flags = divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA);
1630 stream->frequency = divider & 0x7fffff;
1632 device->updateStateBlock->changed.streamFreq |= 1 << stream_idx;
1634 if (stream->frequency != old_freq || stream->flags != old_flags)
1635 device_invalidate_state(device, STATE_STREAMSRC);
1640 HRESULT CDECL wined3d_device_get_stream_source_freq(const struct wined3d_device *device,
1641 UINT stream_idx, UINT *divider)
1643 struct wined3d_stream_state *stream;
1645 TRACE("device %p, stream_idx %u, divider %p.\n", device, stream_idx, divider);
1647 stream = &device->updateStateBlock->state.streams[stream_idx];
1648 *divider = stream->flags | stream->frequency;
1650 TRACE("Returning %#x.\n", *divider);
1655 void CDECL wined3d_device_set_transform(struct wined3d_device *device,
1656 enum wined3d_transform_state d3dts, const struct wined3d_matrix *matrix)
1658 TRACE("device %p, state %s, matrix %p.\n",
1659 device, debug_d3dtstype(d3dts), matrix);
1660 TRACE("%.8e %.8e %.8e %.8e\n", matrix->u.s._11, matrix->u.s._12, matrix->u.s._13, matrix->u.s._14);
1661 TRACE("%.8e %.8e %.8e %.8e\n", matrix->u.s._21, matrix->u.s._22, matrix->u.s._23, matrix->u.s._24);
1662 TRACE("%.8e %.8e %.8e %.8e\n", matrix->u.s._31, matrix->u.s._32, matrix->u.s._33, matrix->u.s._34);
1663 TRACE("%.8e %.8e %.8e %.8e\n", matrix->u.s._41, matrix->u.s._42, matrix->u.s._43, matrix->u.s._44);
1665 /* Handle recording of state blocks. */
1666 if (device->isRecordingState)
1668 TRACE("Recording... not performing anything.\n");
1669 device->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
1670 device->updateStateBlock->state.transforms[d3dts] = *matrix;
1674 /* If the new matrix is the same as the current one,
1675 * we cut off any further processing. this seems to be a reasonable
1676 * optimization because as was noticed, some apps (warcraft3 for example)
1677 * tend towards setting the same matrix repeatedly for some reason.
1679 * From here on we assume that the new matrix is different, wherever it matters. */
1680 if (!memcmp(&device->stateBlock->state.transforms[d3dts].u.m[0][0], matrix, sizeof(*matrix)))
1682 TRACE("The application is setting the same matrix over again.\n");
1686 device->stateBlock->state.transforms[d3dts] = *matrix;
1687 if (d3dts == WINED3D_TS_VIEW)
1688 device->view_ident = !memcmp(matrix, &identity, sizeof(identity));
1690 if (d3dts < WINED3D_TS_WORLD_MATRIX(device->adapter->gl_info.limits.blends))
1691 device_invalidate_state(device, STATE_TRANSFORM(d3dts));
1694 void CDECL wined3d_device_get_transform(const struct wined3d_device *device,
1695 enum wined3d_transform_state state, struct wined3d_matrix *matrix)
1697 TRACE("device %p, state %s, matrix %p.\n", device, debug_d3dtstype(state), matrix);
1699 *matrix = device->stateBlock->state.transforms[state];
1702 void CDECL wined3d_device_multiply_transform(struct wined3d_device *device,
1703 enum wined3d_transform_state state, const struct wined3d_matrix *matrix)
1705 const struct wined3d_matrix *mat;
1706 struct wined3d_matrix temp;
1708 TRACE("device %p, state %s, matrix %p.\n", device, debug_d3dtstype(state), matrix);
1710 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
1711 * below means it will be recorded in a state block change, but it
1712 * works regardless where it is recorded.
1713 * If this is found to be wrong, change to StateBlock. */
1714 if (state > HIGHEST_TRANSFORMSTATE)
1716 WARN("Unhandled transform state %#x.\n", state);
1720 mat = &device->updateStateBlock->state.transforms[state];
1721 multiply_matrix(&temp, mat, matrix);
1723 /* Apply change via set transform - will reapply to eg. lights this way. */
1724 wined3d_device_set_transform(device, state, &temp);
1727 /* Note lights are real special cases. Although the device caps state only
1728 * e.g. 8 are supported, you can reference any indexes you want as long as
1729 * that number max are enabled at any one point in time. Therefore since the
1730 * indices can be anything, we need a hashmap of them. However, this causes
1731 * stateblock problems. When capturing the state block, I duplicate the
1732 * hashmap, but when recording, just build a chain pretty much of commands to
1734 HRESULT CDECL wined3d_device_set_light(struct wined3d_device *device,
1735 UINT light_idx, const struct wined3d_light *light)
1737 UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
1738 struct wined3d_light_info *object = NULL;
1742 TRACE("device %p, light_idx %u, light %p.\n", device, light_idx, light);
1744 /* Check the parameter range. Need for speed most wanted sets junk lights
1745 * which confuse the GL driver. */
1747 return WINED3DERR_INVALIDCALL;
1749 switch (light->type)
1751 case WINED3D_LIGHT_POINT:
1752 case WINED3D_LIGHT_SPOT:
1753 case WINED3D_LIGHT_PARALLELPOINT:
1754 case WINED3D_LIGHT_GLSPOT:
1755 /* Incorrect attenuation values can cause the gl driver to crash.
1756 * Happens with Need for speed most wanted. */
1757 if (light->attenuation0 < 0.0f || light->attenuation1 < 0.0f || light->attenuation2 < 0.0f)
1759 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL.\n");
1760 return WINED3DERR_INVALIDCALL;
1764 case WINED3D_LIGHT_DIRECTIONAL:
1765 /* Ignores attenuation */
1769 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
1770 return WINED3DERR_INVALIDCALL;
1773 LIST_FOR_EACH(e, &device->updateStateBlock->state.light_map[hash_idx])
1775 object = LIST_ENTRY(e, struct wined3d_light_info, entry);
1776 if (object->OriginalIndex == light_idx)
1783 TRACE("Adding new light\n");
1784 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1786 return E_OUTOFMEMORY;
1788 list_add_head(&device->updateStateBlock->state.light_map[hash_idx], &object->entry);
1789 object->glIndex = -1;
1790 object->OriginalIndex = light_idx;
1793 /* Initialize the object. */
1794 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n",
1795 light_idx, light->type,
1796 light->diffuse.r, light->diffuse.g, light->diffuse.b, light->diffuse.a,
1797 light->specular.r, light->specular.g, light->specular.b, light->specular.a,
1798 light->ambient.r, light->ambient.g, light->ambient.b, light->ambient.a);
1799 TRACE("... Pos(%f,%f,%f), Dir(%f,%f,%f)\n", light->position.x, light->position.y, light->position.z,
1800 light->direction.x, light->direction.y, light->direction.z);
1801 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n",
1802 light->range, light->falloff, light->theta, light->phi);
1804 /* Save away the information. */
1805 object->OriginalParms = *light;
1807 switch (light->type)
1809 case WINED3D_LIGHT_POINT:
1811 object->lightPosn[0] = light->position.x;
1812 object->lightPosn[1] = light->position.y;
1813 object->lightPosn[2] = light->position.z;
1814 object->lightPosn[3] = 1.0f;
1815 object->cutoff = 180.0f;
1819 case WINED3D_LIGHT_DIRECTIONAL:
1821 object->lightPosn[0] = -light->direction.x;
1822 object->lightPosn[1] = -light->direction.y;
1823 object->lightPosn[2] = -light->direction.z;
1824 object->lightPosn[3] = 0.0f;
1825 object->exponent = 0.0f;
1826 object->cutoff = 180.0f;
1829 case WINED3D_LIGHT_SPOT:
1831 object->lightPosn[0] = light->position.x;
1832 object->lightPosn[1] = light->position.y;
1833 object->lightPosn[2] = light->position.z;
1834 object->lightPosn[3] = 1.0f;
1837 object->lightDirn[0] = light->direction.x;
1838 object->lightDirn[1] = light->direction.y;
1839 object->lightDirn[2] = light->direction.z;
1840 object->lightDirn[3] = 1.0f;
1842 /* opengl-ish and d3d-ish spot lights use too different models
1843 * for the light "intensity" as a function of the angle towards
1844 * the main light direction, so we only can approximate very
1845 * roughly. However, spot lights are rather rarely used in games
1846 * (if ever used at all). Furthermore if still used, probably
1847 * nobody pays attention to such details. */
1848 if (!light->falloff)
1850 /* Falloff = 0 is easy, because d3d's and opengl's spot light
1851 * equations have the falloff resp. exponent parameter as an
1852 * exponent, so the spot light lighting will always be 1.0 for
1853 * both of them, and we don't have to care for the rest of the
1854 * rather complex calculation. */
1855 object->exponent = 0.0f;
1859 rho = light->theta + (light->phi - light->theta) / (2 * light->falloff);
1862 object->exponent = -0.3f / logf(cosf(rho / 2));
1865 if (object->exponent > 128.0f)
1866 object->exponent = 128.0f;
1868 object->cutoff = (float)(light->phi * 90 / M_PI);
1873 FIXME("Unrecognized light type %#x.\n", light->type);
1876 /* Update the live definitions if the light is currently assigned a glIndex. */
1877 if (object->glIndex != -1 && !device->isRecordingState)
1878 device_invalidate_state(device, STATE_ACTIVELIGHT(object->glIndex));
1883 HRESULT CDECL wined3d_device_get_light(const struct wined3d_device *device,
1884 UINT light_idx, struct wined3d_light *light)
1886 UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
1887 struct wined3d_light_info *light_info = NULL;
1890 TRACE("device %p, light_idx %u, light %p.\n", device, light_idx, light);
1892 LIST_FOR_EACH(e, &device->stateBlock->state.light_map[hash_idx])
1894 light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
1895 if (light_info->OriginalIndex == light_idx)
1902 TRACE("Light information requested but light not defined\n");
1903 return WINED3DERR_INVALIDCALL;
1906 *light = light_info->OriginalParms;
1910 HRESULT CDECL wined3d_device_set_light_enable(struct wined3d_device *device, UINT light_idx, BOOL enable)
1912 UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
1913 struct wined3d_light_info *light_info = NULL;
1916 TRACE("device %p, light_idx %u, enable %#x.\n", device, light_idx, enable);
1918 LIST_FOR_EACH(e, &device->updateStateBlock->state.light_map[hash_idx])
1920 light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
1921 if (light_info->OriginalIndex == light_idx)
1925 TRACE("Found light %p.\n", light_info);
1927 /* Special case - enabling an undefined light creates one with a strict set of parameters. */
1930 TRACE("Light enabled requested but light not defined, so defining one!\n");
1931 wined3d_device_set_light(device, light_idx, &WINED3D_default_light);
1933 /* Search for it again! Should be fairly quick as near head of list. */
1934 LIST_FOR_EACH(e, &device->updateStateBlock->state.light_map[hash_idx])
1936 light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
1937 if (light_info->OriginalIndex == light_idx)
1943 FIXME("Adding default lights has failed dismally\n");
1944 return WINED3DERR_INVALIDCALL;
1950 if (light_info->glIndex != -1)
1952 if (!device->isRecordingState)
1953 device_invalidate_state(device, STATE_ACTIVELIGHT(light_info->glIndex));
1955 device->updateStateBlock->state.lights[light_info->glIndex] = NULL;
1956 light_info->glIndex = -1;
1960 TRACE("Light already disabled, nothing to do\n");
1962 light_info->enabled = FALSE;
1966 light_info->enabled = TRUE;
1967 if (light_info->glIndex != -1)
1969 TRACE("Nothing to do as light was enabled\n");
1974 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1975 /* Find a free GL light. */
1976 for (i = 0; i < gl_info->limits.lights; ++i)
1978 if (!device->updateStateBlock->state.lights[i])
1980 device->updateStateBlock->state.lights[i] = light_info;
1981 light_info->glIndex = i;
1985 if (light_info->glIndex == -1)
1987 /* Our tests show that Windows returns D3D_OK in this situation, even with
1988 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
1989 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
1990 * as well for those lights.
1992 * TODO: Test how this affects rendering. */
1993 WARN("Too many concurrently active lights\n");
1997 /* i == light_info->glIndex */
1998 if (!device->isRecordingState)
1999 device_invalidate_state(device, STATE_ACTIVELIGHT(i));
2006 HRESULT CDECL wined3d_device_get_light_enable(const struct wined3d_device *device, UINT light_idx, BOOL *enable)
2008 UINT hash_idx = LIGHTMAP_HASHFUNC(light_idx);
2009 struct wined3d_light_info *light_info = NULL;
2012 TRACE("device %p, light_idx %u, enable %p.\n", device, light_idx, enable);
2014 LIST_FOR_EACH(e, &device->stateBlock->state.light_map[hash_idx])
2016 light_info = LIST_ENTRY(e, struct wined3d_light_info, entry);
2017 if (light_info->OriginalIndex == light_idx)
2024 TRACE("Light enabled state requested but light not defined.\n");
2025 return WINED3DERR_INVALIDCALL;
2027 /* true is 128 according to SetLightEnable */
2028 *enable = light_info->enabled ? 128 : 0;
2032 HRESULT CDECL wined3d_device_set_clip_plane(struct wined3d_device *device,
2033 UINT plane_idx, const struct wined3d_vec4 *plane)
2035 TRACE("device %p, plane_idx %u, plane %p.\n", device, plane_idx, plane);
2037 /* Validate plane_idx. */
2038 if (plane_idx >= device->adapter->gl_info.limits.clipplanes)
2040 TRACE("Application has requested clipplane this device doesn't support.\n");
2041 return WINED3DERR_INVALIDCALL;
2044 device->updateStateBlock->changed.clipplane |= 1 << plane_idx;
2046 if (!memcmp(&device->updateStateBlock->state.clip_planes[plane_idx], plane, sizeof(*plane)))
2048 TRACE("Application is setting old values over, nothing to do.\n");
2052 device->updateStateBlock->state.clip_planes[plane_idx] = *plane;
2054 /* Handle recording of state blocks. */
2055 if (device->isRecordingState)
2057 TRACE("Recording... not performing anything.\n");
2061 device_invalidate_state(device, STATE_CLIPPLANE(plane_idx));
2066 HRESULT CDECL wined3d_device_get_clip_plane(const struct wined3d_device *device,
2067 UINT plane_idx, struct wined3d_vec4 *plane)
2069 TRACE("device %p, plane_idx %u, plane %p.\n", device, plane_idx, plane);
2071 /* Validate plane_idx. */
2072 if (plane_idx >= device->adapter->gl_info.limits.clipplanes)
2074 TRACE("Application has requested clipplane this device doesn't support.\n");
2075 return WINED3DERR_INVALIDCALL;
2078 *plane = device->stateBlock->state.clip_planes[plane_idx];
2083 HRESULT CDECL wined3d_device_set_clip_status(struct wined3d_device *device,
2084 const struct wined3d_clip_status *clip_status)
2086 FIXME("device %p, clip_status %p stub!\n", device, clip_status);
2089 return WINED3DERR_INVALIDCALL;
2094 HRESULT CDECL wined3d_device_get_clip_status(const struct wined3d_device *device,
2095 struct wined3d_clip_status *clip_status)
2097 FIXME("device %p, clip_status %p stub!\n", device, clip_status);
2100 return WINED3DERR_INVALIDCALL;
2105 void CDECL wined3d_device_set_material(struct wined3d_device *device, const struct wined3d_material *material)
2107 TRACE("device %p, material %p.\n", device, material);
2109 device->updateStateBlock->changed.material = TRUE;
2110 device->updateStateBlock->state.material = *material;
2112 /* Handle recording of state blocks */
2113 if (device->isRecordingState)
2115 TRACE("Recording... not performing anything.\n");
2119 device_invalidate_state(device, STATE_MATERIAL);
2122 void CDECL wined3d_device_get_material(const struct wined3d_device *device, struct wined3d_material *material)
2124 TRACE("device %p, material %p.\n", device, material);
2126 *material = device->updateStateBlock->state.material;
2128 TRACE("diffuse {%.8e, %.8e, %.8e, %.8e}\n",
2129 material->diffuse.r, material->diffuse.g,
2130 material->diffuse.b, material->diffuse.a);
2131 TRACE("ambient {%.8e, %.8e, %.8e, %.8e}\n",
2132 material->ambient.r, material->ambient.g,
2133 material->ambient.b, material->ambient.a);
2134 TRACE("specular {%.8e, %.8e, %.8e, %.8e}\n",
2135 material->specular.r, material->specular.g,
2136 material->specular.b, material->specular.a);
2137 TRACE("emissive {%.8e, %.8e, %.8e, %.8e}\n",
2138 material->emissive.r, material->emissive.g,
2139 material->emissive.b, material->emissive.a);
2140 TRACE("power %.8e.\n", material->power);
2143 void CDECL wined3d_device_set_index_buffer(struct wined3d_device *device,
2144 struct wined3d_buffer *buffer, enum wined3d_format_id format_id)
2146 struct wined3d_buffer *prev_buffer;
2148 TRACE("device %p, buffer %p, format %s.\n",
2149 device, buffer, debug_d3dformat(format_id));
2151 prev_buffer = device->updateStateBlock->state.index_buffer;
2153 device->updateStateBlock->changed.indices = TRUE;
2154 device->updateStateBlock->state.index_buffer = buffer;
2155 device->updateStateBlock->state.index_format = format_id;
2157 /* Handle recording of state blocks. */
2158 if (device->isRecordingState)
2160 TRACE("Recording... not performing anything.\n");
2162 wined3d_buffer_incref(buffer);
2164 wined3d_buffer_decref(prev_buffer);
2168 if (prev_buffer != buffer)
2170 device_invalidate_state(device, STATE_INDEXBUFFER);
2173 InterlockedIncrement(&buffer->resource.bind_count);
2174 wined3d_buffer_incref(buffer);
2178 InterlockedDecrement(&prev_buffer->resource.bind_count);
2179 wined3d_buffer_decref(prev_buffer);
2184 struct wined3d_buffer * CDECL wined3d_device_get_index_buffer(const struct wined3d_device *device,
2185 enum wined3d_format_id *format)
2187 TRACE("device %p, format %p.\n", device, format);
2189 *format = device->stateBlock->state.index_format;
2190 return device->stateBlock->state.index_buffer;
2193 void CDECL wined3d_device_set_base_vertex_index(struct wined3d_device *device, INT base_index)
2195 TRACE("device %p, base_index %d.\n", device, base_index);
2197 device->updateStateBlock->state.base_vertex_index = base_index;
2200 INT CDECL wined3d_device_get_base_vertex_index(const struct wined3d_device *device)
2202 TRACE("device %p.\n", device);
2204 return device->stateBlock->state.base_vertex_index;
2207 void CDECL wined3d_device_set_viewport(struct wined3d_device *device, const struct wined3d_viewport *viewport)
2209 TRACE("device %p, viewport %p.\n", device, viewport);
2210 TRACE("x %u, y %u, w %u, h %u, min_z %.8e, max_z %.8e.\n",
2211 viewport->x, viewport->y, viewport->width, viewport->height, viewport->min_z, viewport->max_z);
2213 device->updateStateBlock->changed.viewport = TRUE;
2214 device->updateStateBlock->state.viewport = *viewport;
2216 /* Handle recording of state blocks */
2217 if (device->isRecordingState)
2219 TRACE("Recording... not performing anything\n");
2223 device_invalidate_state(device, STATE_VIEWPORT);
2226 void CDECL wined3d_device_get_viewport(const struct wined3d_device *device, struct wined3d_viewport *viewport)
2228 TRACE("device %p, viewport %p.\n", device, viewport);
2230 *viewport = device->stateBlock->state.viewport;
2233 static void resolve_depth_buffer(struct wined3d_state *state)
2235 struct wined3d_texture *texture = state->textures[0];
2236 struct wined3d_surface *depth_stencil, *surface;
2238 if (!texture || texture->resource.type != WINED3D_RTYPE_TEXTURE
2239 || !(texture->resource.format->flags & WINED3DFMT_FLAG_DEPTH))
2241 surface = surface_from_resource(texture->sub_resources[0]);
2242 depth_stencil = state->fb->depth_stencil;
2246 wined3d_surface_blt(surface, NULL, depth_stencil, NULL, 0, NULL, WINED3D_TEXF_POINT);
2249 void CDECL wined3d_device_set_render_state(struct wined3d_device *device,
2250 enum wined3d_render_state state, DWORD value)
2252 DWORD old_value = device->stateBlock->state.render_states[state];
2254 TRACE("device %p, state %s (%#x), value %#x.\n", device, debug_d3drenderstate(state), state, value);
2256 device->updateStateBlock->changed.renderState[state >> 5] |= 1 << (state & 0x1f);
2257 device->updateStateBlock->state.render_states[state] = value;
2259 /* Handle recording of state blocks. */
2260 if (device->isRecordingState)
2262 TRACE("Recording... not performing anything.\n");
2266 /* Compared here and not before the assignment to allow proper stateblock recording. */
2267 if (value == old_value)
2268 TRACE("Application is setting the old value over, nothing to do.\n");
2270 device_invalidate_state(device, STATE_RENDER(state));
2272 if (state == WINED3D_RS_POINTSIZE && value == WINED3D_RESZ_CODE)
2274 TRACE("RESZ multisampled depth buffer resolve triggered.\n");
2275 resolve_depth_buffer(&device->stateBlock->state);
2279 DWORD CDECL wined3d_device_get_render_state(const struct wined3d_device *device, enum wined3d_render_state state)
2281 TRACE("device %p, state %s (%#x).\n", device, debug_d3drenderstate(state), state);
2283 return device->stateBlock->state.render_states[state];
2286 void CDECL wined3d_device_set_sampler_state(struct wined3d_device *device,
2287 UINT sampler_idx, enum wined3d_sampler_state state, DWORD value)
2291 TRACE("device %p, sampler_idx %u, state %s, value %#x.\n",
2292 device, sampler_idx, debug_d3dsamplerstate(state), value);
2294 if (sampler_idx >= WINED3DVERTEXTEXTURESAMPLER0 && sampler_idx <= WINED3DVERTEXTEXTURESAMPLER3)
2295 sampler_idx -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2297 if (sampler_idx >= sizeof(device->stateBlock->state.sampler_states)
2298 / sizeof(*device->stateBlock->state.sampler_states))
2300 WARN("Invalid sampler %u.\n", sampler_idx);
2301 return; /* Windows accepts overflowing this array ... we do not. */
2304 old_value = device->stateBlock->state.sampler_states[sampler_idx][state];
2305 device->updateStateBlock->state.sampler_states[sampler_idx][state] = value;
2306 device->updateStateBlock->changed.samplerState[sampler_idx] |= 1 << state;
2308 /* Handle recording of state blocks. */
2309 if (device->isRecordingState)
2311 TRACE("Recording... not performing anything.\n");
2315 if (old_value == value)
2317 TRACE("Application is setting the old value over, nothing to do.\n");
2321 device_invalidate_state(device, STATE_SAMPLER(sampler_idx));
2324 DWORD CDECL wined3d_device_get_sampler_state(const struct wined3d_device *device,
2325 UINT sampler_idx, enum wined3d_sampler_state state)
2327 TRACE("device %p, sampler_idx %u, state %s.\n",
2328 device, sampler_idx, debug_d3dsamplerstate(state));
2330 if (sampler_idx >= WINED3DVERTEXTEXTURESAMPLER0 && sampler_idx <= WINED3DVERTEXTEXTURESAMPLER3)
2331 sampler_idx -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2333 if (sampler_idx >= sizeof(device->stateBlock->state.sampler_states)
2334 / sizeof(*device->stateBlock->state.sampler_states))
2336 WARN("Invalid sampler %u.\n", sampler_idx);
2337 return 0; /* Windows accepts overflowing this array ... we do not. */
2340 return device->stateBlock->state.sampler_states[sampler_idx][state];
2343 void CDECL wined3d_device_set_scissor_rect(struct wined3d_device *device, const RECT *rect)
2345 TRACE("device %p, rect %s.\n", device, wine_dbgstr_rect(rect));
2347 device->updateStateBlock->changed.scissorRect = TRUE;
2348 if (EqualRect(&device->updateStateBlock->state.scissor_rect, rect))
2350 TRACE("App is setting the old scissor rectangle over, nothing to do.\n");
2353 CopyRect(&device->updateStateBlock->state.scissor_rect, rect);
2355 if (device->isRecordingState)
2357 TRACE("Recording... not performing anything.\n");
2361 device_invalidate_state(device, STATE_SCISSORRECT);
2364 void CDECL wined3d_device_get_scissor_rect(const struct wined3d_device *device, RECT *rect)
2366 TRACE("device %p, rect %p.\n", device, rect);
2368 *rect = device->updateStateBlock->state.scissor_rect;
2369 TRACE("Returning rect %s.\n", wine_dbgstr_rect(rect));
2372 void CDECL wined3d_device_set_vertex_declaration(struct wined3d_device *device,
2373 struct wined3d_vertex_declaration *declaration)
2375 struct wined3d_vertex_declaration *prev = device->updateStateBlock->state.vertex_declaration;
2377 TRACE("device %p, declaration %p.\n", device, declaration);
2380 wined3d_vertex_declaration_incref(declaration);
2382 wined3d_vertex_declaration_decref(prev);
2384 device->updateStateBlock->state.vertex_declaration = declaration;
2385 device->updateStateBlock->changed.vertexDecl = TRUE;
2387 if (device->isRecordingState)
2389 TRACE("Recording... not performing anything.\n");
2393 if (declaration == prev)
2395 /* Checked after the assignment to allow proper stateblock recording. */
2396 TRACE("Application is setting the old declaration over, nothing to do.\n");
2400 device_invalidate_state(device, STATE_VDECL);
2403 struct wined3d_vertex_declaration * CDECL wined3d_device_get_vertex_declaration(const struct wined3d_device *device)
2405 TRACE("device %p.\n", device);
2407 return device->stateBlock->state.vertex_declaration;
2410 void CDECL wined3d_device_set_vertex_shader(struct wined3d_device *device, struct wined3d_shader *shader)
2412 struct wined3d_shader *prev = device->updateStateBlock->state.vertex_shader;
2414 TRACE("device %p, shader %p.\n", device, shader);
2417 wined3d_shader_incref(shader);
2419 wined3d_shader_decref(prev);
2421 device->updateStateBlock->state.vertex_shader = shader;
2422 device->updateStateBlock->changed.vertexShader = TRUE;
2424 if (device->isRecordingState)
2426 TRACE("Recording... not performing anything.\n");
2432 TRACE("Application is setting the old shader over, nothing to do.\n");
2436 device_invalidate_state(device, STATE_VSHADER);
2439 struct wined3d_shader * CDECL wined3d_device_get_vertex_shader(const struct wined3d_device *device)
2441 TRACE("device %p.\n", device);
2443 return device->stateBlock->state.vertex_shader;
2446 void CDECL wined3d_device_set_vs_cb(struct wined3d_device *device, UINT idx, struct wined3d_buffer *buffer)
2448 struct wined3d_buffer *prev;
2450 TRACE("device %p, idx %u, buffer %p.\n", device, idx, buffer);
2452 if (idx >= MAX_CONSTANT_BUFFERS)
2454 WARN("Invalid constant buffer index %u.\n", idx);
2458 prev = device->updateStateBlock->state.vs_cb[idx];
2459 device->updateStateBlock->state.vs_cb[idx] = buffer;
2461 if (device->isRecordingState)
2464 wined3d_buffer_incref(buffer);
2466 wined3d_buffer_decref(prev);
2474 InterlockedIncrement(&buffer->resource.bind_count);
2475 wined3d_buffer_incref(buffer);
2479 InterlockedDecrement(&prev->resource.bind_count);
2480 wined3d_buffer_decref(prev);
2485 struct wined3d_buffer * CDECL wined3d_device_get_vs_cb(const struct wined3d_device *device, UINT idx)
2487 TRACE("device %p, idx %u.\n", device, idx);
2489 if (idx >= MAX_CONSTANT_BUFFERS)
2491 WARN("Invalid constant buffer index %u.\n", idx);
2495 return device->stateBlock->state.vs_cb[idx];
2498 void CDECL wined3d_device_set_vs_sampler(struct wined3d_device *device, UINT idx, struct wined3d_sampler *sampler)
2500 struct wined3d_sampler *prev;
2502 TRACE("device %p, idx %u, sampler %p.\n", device, idx, sampler);
2504 if (idx >= MAX_SAMPLER_OBJECTS)
2506 WARN("Invalid sampler index %u.\n", idx);
2510 prev = device->updateStateBlock->state.vs_sampler[idx];
2511 device->updateStateBlock->state.vs_sampler[idx] = sampler;
2514 wined3d_sampler_incref(sampler);
2516 wined3d_sampler_decref(prev);
2519 struct wined3d_sampler * CDECL wined3d_device_get_vs_sampler(const struct wined3d_device *device, UINT idx)
2521 TRACE("device %p, idx %u.\n", device, idx);
2523 if (idx >= MAX_SAMPLER_OBJECTS)
2525 WARN("Invalid sampler index %u.\n", idx);
2529 return device->stateBlock->state.vs_sampler[idx];
2532 HRESULT CDECL wined3d_device_set_vs_consts_b(struct wined3d_device *device,
2533 UINT start_register, const BOOL *constants, UINT bool_count)
2535 UINT count = min(bool_count, MAX_CONST_B - start_register);
2538 TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
2539 device, start_register, constants, bool_count);
2541 if (!constants || start_register >= MAX_CONST_B)
2542 return WINED3DERR_INVALIDCALL;
2544 memcpy(&device->updateStateBlock->state.vs_consts_b[start_register], constants, count * sizeof(BOOL));
2545 for (i = 0; i < count; ++i)
2546 TRACE("Set BOOL constant %u to %s.\n", start_register + i, constants[i] ? "true" : "false");
2548 for (i = start_register; i < count + start_register; ++i)
2549 device->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
2551 if (!device->isRecordingState)
2552 device_invalidate_state(device, STATE_VERTEXSHADERCONSTANT);
2557 HRESULT CDECL wined3d_device_get_vs_consts_b(const struct wined3d_device *device,
2558 UINT start_register, BOOL *constants, UINT bool_count)
2560 UINT count = min(bool_count, MAX_CONST_B - start_register);
2562 TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
2563 device, start_register, constants, bool_count);
2565 if (!constants || start_register >= MAX_CONST_B)
2566 return WINED3DERR_INVALIDCALL;
2568 memcpy(constants, &device->stateBlock->state.vs_consts_b[start_register], count * sizeof(BOOL));
2573 HRESULT CDECL wined3d_device_set_vs_consts_i(struct wined3d_device *device,
2574 UINT start_register, const int *constants, UINT vector4i_count)
2576 UINT count = min(vector4i_count, MAX_CONST_I - start_register);
2579 TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
2580 device, start_register, constants, vector4i_count);
2582 if (!constants || start_register >= MAX_CONST_I)
2583 return WINED3DERR_INVALIDCALL;
2585 memcpy(&device->updateStateBlock->state.vs_consts_i[start_register * 4], constants, count * sizeof(int) * 4);
2586 for (i = 0; i < count; ++i)
2587 TRACE("Set INT constant %u to {%d, %d, %d, %d}.\n", start_register + i,
2588 constants[i * 4], constants[i * 4 + 1],
2589 constants[i * 4 + 2], constants[i * 4 + 3]);
2591 for (i = start_register; i < count + start_register; ++i)
2592 device->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
2594 if (!device->isRecordingState)
2595 device_invalidate_state(device, STATE_VERTEXSHADERCONSTANT);
2600 HRESULT CDECL wined3d_device_get_vs_consts_i(const struct wined3d_device *device,
2601 UINT start_register, int *constants, UINT vector4i_count)
2603 UINT count = min(vector4i_count, MAX_CONST_I - start_register);
2605 TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
2606 device, start_register, constants, vector4i_count);
2608 if (!constants || start_register >= MAX_CONST_I)
2609 return WINED3DERR_INVALIDCALL;
2611 memcpy(constants, &device->stateBlock->state.vs_consts_i[start_register * 4], count * sizeof(int) * 4);
2615 HRESULT CDECL wined3d_device_set_vs_consts_f(struct wined3d_device *device,
2616 UINT start_register, const float *constants, UINT vector4f_count)
2620 TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
2621 device, start_register, constants, vector4f_count);
2623 /* Specifically test start_register > limit to catch MAX_UINT overflows
2624 * when adding start_register + vector4f_count. */
2626 || start_register + vector4f_count > device->d3d_vshader_constantF
2627 || start_register > device->d3d_vshader_constantF)
2628 return WINED3DERR_INVALIDCALL;
2630 memcpy(&device->updateStateBlock->state.vs_consts_f[start_register * 4],
2631 constants, vector4f_count * sizeof(float) * 4);
2634 for (i = 0; i < vector4f_count; ++i)
2635 TRACE("Set FLOAT constant %u to {%.8e, %.8e, %.8e, %.8e}.\n", start_register + i,
2636 constants[i * 4], constants[i * 4 + 1],
2637 constants[i * 4 + 2], constants[i * 4 + 3]);
2640 if (!device->isRecordingState)
2642 device->shader_backend->shader_update_float_vertex_constants(device, start_register, vector4f_count);
2643 device_invalidate_state(device, STATE_VERTEXSHADERCONSTANT);
2646 memset(device->updateStateBlock->changed.vertexShaderConstantsF + start_register, 1,
2647 sizeof(*device->updateStateBlock->changed.vertexShaderConstantsF) * vector4f_count);
2652 HRESULT CDECL wined3d_device_get_vs_consts_f(const struct wined3d_device *device,
2653 UINT start_register, float *constants, UINT vector4f_count)
2655 int count = min(vector4f_count, device->d3d_vshader_constantF - start_register);
2657 TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
2658 device, start_register, constants, vector4f_count);
2660 if (!constants || count < 0)
2661 return WINED3DERR_INVALIDCALL;
2663 memcpy(constants, &device->stateBlock->state.vs_consts_f[start_register * 4], count * sizeof(float) * 4);
2668 static void device_invalidate_texture_stage(const struct wined3d_device *device, DWORD stage)
2672 for (i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
2674 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, i));
2678 static void device_map_stage(struct wined3d_device *device, DWORD stage, DWORD unit)
2680 DWORD i = device->rev_tex_unit_map[unit];
2681 DWORD j = device->texUnitMap[stage];
2683 device->texUnitMap[stage] = unit;
2684 if (i != WINED3D_UNMAPPED_STAGE && i != stage)
2685 device->texUnitMap[i] = WINED3D_UNMAPPED_STAGE;
2687 device->rev_tex_unit_map[unit] = stage;
2688 if (j != WINED3D_UNMAPPED_STAGE && j != unit)
2689 device->rev_tex_unit_map[j] = WINED3D_UNMAPPED_STAGE;
2692 static void device_update_fixed_function_usage_map(struct wined3d_device *device)
2696 device->fixed_function_usage_map = 0;
2697 for (i = 0; i < MAX_TEXTURES; ++i)
2699 const struct wined3d_state *state = &device->stateBlock->state;
2700 enum wined3d_texture_op color_op = state->texture_states[i][WINED3D_TSS_COLOR_OP];
2701 enum wined3d_texture_op alpha_op = state->texture_states[i][WINED3D_TSS_ALPHA_OP];
2702 DWORD color_arg1 = state->texture_states[i][WINED3D_TSS_COLOR_ARG1] & WINED3DTA_SELECTMASK;
2703 DWORD color_arg2 = state->texture_states[i][WINED3D_TSS_COLOR_ARG2] & WINED3DTA_SELECTMASK;
2704 DWORD color_arg3 = state->texture_states[i][WINED3D_TSS_COLOR_ARG0] & WINED3DTA_SELECTMASK;
2705 DWORD alpha_arg1 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG1] & WINED3DTA_SELECTMASK;
2706 DWORD alpha_arg2 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG2] & WINED3DTA_SELECTMASK;
2707 DWORD alpha_arg3 = state->texture_states[i][WINED3D_TSS_ALPHA_ARG0] & WINED3DTA_SELECTMASK;
2709 /* Not used, and disable higher stages. */
2710 if (color_op == WINED3D_TOP_DISABLE)
2713 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3D_TOP_SELECT_ARG2)
2714 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3D_TOP_SELECT_ARG1)
2715 || ((color_arg3 == WINED3DTA_TEXTURE)
2716 && (color_op == WINED3D_TOP_MULTIPLY_ADD || color_op == WINED3D_TOP_LERP))
2717 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3D_TOP_SELECT_ARG2)
2718 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3D_TOP_SELECT_ARG1)
2719 || ((alpha_arg3 == WINED3DTA_TEXTURE)
2720 && (alpha_op == WINED3D_TOP_MULTIPLY_ADD || alpha_op == WINED3D_TOP_LERP)))
2721 device->fixed_function_usage_map |= (1 << i);
2723 if ((color_op == WINED3D_TOP_BUMPENVMAP || color_op == WINED3D_TOP_BUMPENVMAP_LUMINANCE)
2724 && i < MAX_TEXTURES - 1)
2725 device->fixed_function_usage_map |= (1 << (i + 1));
2729 static void device_map_fixed_function_samplers(struct wined3d_device *device, const struct wined3d_gl_info *gl_info)
2731 unsigned int i, tex;
2734 device_update_fixed_function_usage_map(device);
2735 ffu_map = device->fixed_function_usage_map;
2737 if (device->max_ffp_textures == gl_info->limits.texture_stages
2738 || device->stateBlock->state.lowest_disabled_stage <= device->max_ffp_textures)
2740 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
2742 if (!(ffu_map & 1)) continue;
2744 if (device->texUnitMap[i] != i)
2746 device_map_stage(device, i, i);
2747 device_invalidate_state(device, STATE_SAMPLER(i));
2748 device_invalidate_texture_stage(device, i);
2754 /* Now work out the mapping */
2756 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
2758 if (!(ffu_map & 1)) continue;
2760 if (device->texUnitMap[i] != tex)
2762 device_map_stage(device, i, tex);
2763 device_invalidate_state(device, STATE_SAMPLER(i));
2764 device_invalidate_texture_stage(device, i);
2771 static void device_map_psamplers(struct wined3d_device *device, const struct wined3d_gl_info *gl_info)
2773 const enum wined3d_sampler_texture_type *sampler_type =
2774 device->stateBlock->state.pixel_shader->reg_maps.sampler_type;
2777 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i)
2779 if (sampler_type[i] && device->texUnitMap[i] != i)
2781 device_map_stage(device, i, i);
2782 device_invalidate_state(device, STATE_SAMPLER(i));
2783 if (i < gl_info->limits.texture_stages)
2784 device_invalidate_texture_stage(device, i);
2789 static BOOL device_unit_free_for_vs(const struct wined3d_device *device,
2790 const enum wined3d_sampler_texture_type *pshader_sampler_tokens,
2791 const enum wined3d_sampler_texture_type *vshader_sampler_tokens, DWORD unit)
2793 DWORD current_mapping = device->rev_tex_unit_map[unit];
2795 /* Not currently used */
2796 if (current_mapping == WINED3D_UNMAPPED_STAGE) return TRUE;
2798 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
2799 /* Used by a fragment sampler */
2801 if (!pshader_sampler_tokens) {
2802 /* No pixel shader, check fixed function */
2803 return current_mapping >= MAX_TEXTURES || !(device->fixed_function_usage_map & (1 << current_mapping));
2806 /* Pixel shader, check the shader's sampler map */
2807 return !pshader_sampler_tokens[current_mapping];
2810 /* Used by a vertex sampler */
2811 return !vshader_sampler_tokens[current_mapping - MAX_FRAGMENT_SAMPLERS];
2814 static void device_map_vsamplers(struct wined3d_device *device, BOOL ps, const struct wined3d_gl_info *gl_info)
2816 const enum wined3d_sampler_texture_type *vshader_sampler_type =
2817 device->stateBlock->state.vertex_shader->reg_maps.sampler_type;
2818 const enum wined3d_sampler_texture_type *pshader_sampler_type = NULL;
2819 int start = min(MAX_COMBINED_SAMPLERS, gl_info->limits.combined_samplers) - 1;
2824 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
2825 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
2826 pshader_sampler_type = device->stateBlock->state.pixel_shader->reg_maps.sampler_type;
2829 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
2830 DWORD vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
2831 if (vshader_sampler_type[i])
2833 if (device->texUnitMap[vsampler_idx] != WINED3D_UNMAPPED_STAGE)
2835 /* Already mapped somewhere */
2841 if (device_unit_free_for_vs(device, pshader_sampler_type, vshader_sampler_type, start))
2843 device_map_stage(device, vsampler_idx, start);
2844 device_invalidate_state(device, STATE_SAMPLER(vsampler_idx));
2856 void device_update_tex_unit_map(struct wined3d_device *device)
2858 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2859 const struct wined3d_state *state = &device->stateBlock->state;
2860 BOOL vs = use_vs(state);
2861 BOOL ps = use_ps(state);
2864 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
2865 * that would be really messy and require shader recompilation
2866 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
2867 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
2870 device_map_psamplers(device, gl_info);
2872 device_map_fixed_function_samplers(device, gl_info);
2875 device_map_vsamplers(device, ps, gl_info);
2878 void CDECL wined3d_device_set_pixel_shader(struct wined3d_device *device, struct wined3d_shader *shader)
2880 struct wined3d_shader *prev = device->updateStateBlock->state.pixel_shader;
2882 TRACE("device %p, shader %p.\n", device, shader);
2885 wined3d_shader_incref(shader);
2887 wined3d_shader_decref(prev);
2889 device->updateStateBlock->state.pixel_shader = shader;
2890 device->updateStateBlock->changed.pixelShader = TRUE;
2892 if (device->isRecordingState)
2894 TRACE("Recording... not performing anything.\n");
2900 TRACE("Application is setting the old shader over, nothing to do.\n");
2904 device_invalidate_state(device, STATE_PIXELSHADER);
2907 struct wined3d_shader * CDECL wined3d_device_get_pixel_shader(const struct wined3d_device *device)
2909 TRACE("device %p.\n", device);
2911 return device->stateBlock->state.pixel_shader;
2914 void CDECL wined3d_device_set_ps_cb(struct wined3d_device *device, UINT idx, struct wined3d_buffer *buffer)
2916 struct wined3d_buffer *prev;
2918 TRACE("device %p, idx %u, buffer %p.\n", device, idx, buffer);
2920 if (idx >= MAX_CONSTANT_BUFFERS)
2922 WARN("Invalid constant buffer index %u.\n", idx);
2926 prev = device->updateStateBlock->state.ps_cb[idx];
2927 device->updateStateBlock->state.ps_cb[idx] = buffer;
2929 if (device->isRecordingState)
2932 wined3d_buffer_incref(buffer);
2934 wined3d_buffer_decref(prev);
2942 InterlockedIncrement(&buffer->resource.bind_count);
2943 wined3d_buffer_incref(buffer);
2947 InterlockedDecrement(&prev->resource.bind_count);
2948 wined3d_buffer_decref(prev);
2953 struct wined3d_buffer * CDECL wined3d_device_get_ps_cb(const struct wined3d_device *device, UINT idx)
2955 TRACE("device %p, idx %u.\n", device, idx);
2957 if (idx >= MAX_CONSTANT_BUFFERS)
2959 WARN("Invalid constant buffer index %u.\n", idx);
2963 return device->stateBlock->state.ps_cb[idx];
2966 void CDECL wined3d_device_set_ps_sampler(struct wined3d_device *device, UINT idx, struct wined3d_sampler *sampler)
2968 struct wined3d_sampler *prev;
2970 TRACE("device %p, idx %u, sampler %p.\n", device, idx, sampler);
2972 if (idx >= MAX_SAMPLER_OBJECTS)
2974 WARN("Invalid sampler index %u.\n", idx);
2978 prev = device->updateStateBlock->state.ps_sampler[idx];
2979 device->updateStateBlock->state.ps_sampler[idx] = sampler;
2982 wined3d_sampler_incref(sampler);
2984 wined3d_sampler_decref(prev);
2987 struct wined3d_sampler * CDECL wined3d_device_get_ps_sampler(const struct wined3d_device *device, UINT idx)
2989 TRACE("device %p, idx %u.\n", device, idx);
2991 if (idx >= MAX_SAMPLER_OBJECTS)
2993 WARN("Invalid sampler index %u.\n", idx);
2997 return device->stateBlock->state.ps_sampler[idx];
3000 HRESULT CDECL wined3d_device_set_ps_consts_b(struct wined3d_device *device,
3001 UINT start_register, const BOOL *constants, UINT bool_count)
3003 UINT count = min(bool_count, MAX_CONST_B - start_register);
3006 TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
3007 device, start_register, constants, bool_count);
3009 if (!constants || start_register >= MAX_CONST_B)
3010 return WINED3DERR_INVALIDCALL;
3012 memcpy(&device->updateStateBlock->state.ps_consts_b[start_register], constants, count * sizeof(BOOL));
3013 for (i = 0; i < count; ++i)
3014 TRACE("Set BOOL constant %u to %s.\n", start_register + i, constants[i] ? "true" : "false");
3016 for (i = start_register; i < count + start_register; ++i)
3017 device->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3019 if (!device->isRecordingState)
3020 device_invalidate_state(device, STATE_PIXELSHADERCONSTANT);
3025 HRESULT CDECL wined3d_device_get_ps_consts_b(const struct wined3d_device *device,
3026 UINT start_register, BOOL *constants, UINT bool_count)
3028 UINT count = min(bool_count, MAX_CONST_B - start_register);
3030 TRACE("device %p, start_register %u, constants %p, bool_count %u.\n",
3031 device, start_register, constants, bool_count);
3033 if (!constants || start_register >= MAX_CONST_B)
3034 return WINED3DERR_INVALIDCALL;
3036 memcpy(constants, &device->stateBlock->state.ps_consts_b[start_register], count * sizeof(BOOL));
3041 HRESULT CDECL wined3d_device_set_ps_consts_i(struct wined3d_device *device,
3042 UINT start_register, const int *constants, UINT vector4i_count)
3044 UINT count = min(vector4i_count, MAX_CONST_I - start_register);
3047 TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
3048 device, start_register, constants, vector4i_count);
3050 if (!constants || start_register >= MAX_CONST_I)
3051 return WINED3DERR_INVALIDCALL;
3053 memcpy(&device->updateStateBlock->state.ps_consts_i[start_register * 4], constants, count * sizeof(int) * 4);
3054 for (i = 0; i < count; ++i)
3055 TRACE("Set INT constant %u to {%d, %d, %d, %d}.\n", start_register + i,
3056 constants[i * 4], constants[i * 4 + 1],
3057 constants[i * 4 + 2], constants[i * 4 + 3]);
3059 for (i = start_register; i < count + start_register; ++i)
3060 device->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3062 if (!device->isRecordingState)
3063 device_invalidate_state(device, STATE_PIXELSHADERCONSTANT);
3068 HRESULT CDECL wined3d_device_get_ps_consts_i(const struct wined3d_device *device,
3069 UINT start_register, int *constants, UINT vector4i_count)
3071 UINT count = min(vector4i_count, MAX_CONST_I - start_register);
3073 TRACE("device %p, start_register %u, constants %p, vector4i_count %u.\n",
3074 device, start_register, constants, vector4i_count);
3076 if (!constants || start_register >= MAX_CONST_I)
3077 return WINED3DERR_INVALIDCALL;
3079 memcpy(constants, &device->stateBlock->state.ps_consts_i[start_register * 4], count * sizeof(int) * 4);
3084 HRESULT CDECL wined3d_device_set_ps_consts_f(struct wined3d_device *device,
3085 UINT start_register, const float *constants, UINT vector4f_count)
3089 TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
3090 device, start_register, constants, vector4f_count);
3092 /* Specifically test start_register > limit to catch MAX_UINT overflows
3093 * when adding start_register + vector4f_count. */
3095 || start_register + vector4f_count > device->d3d_pshader_constantF
3096 || start_register > device->d3d_pshader_constantF)
3097 return WINED3DERR_INVALIDCALL;
3099 memcpy(&device->updateStateBlock->state.ps_consts_f[start_register * 4],
3100 constants, vector4f_count * sizeof(float) * 4);
3103 for (i = 0; i < vector4f_count; ++i)
3104 TRACE("Set FLOAT constant %u to {%.8e, %.8e, %.8e, %.8e}.\n", start_register + i,
3105 constants[i * 4], constants[i * 4 + 1],
3106 constants[i * 4 + 2], constants[i * 4 + 3]);
3109 if (!device->isRecordingState)
3111 device->shader_backend->shader_update_float_pixel_constants(device, start_register, vector4f_count);
3112 device_invalidate_state(device, STATE_PIXELSHADERCONSTANT);
3115 memset(device->updateStateBlock->changed.pixelShaderConstantsF + start_register, 1,
3116 sizeof(*device->updateStateBlock->changed.pixelShaderConstantsF) * vector4f_count);
3121 HRESULT CDECL wined3d_device_get_ps_consts_f(const struct wined3d_device *device,
3122 UINT start_register, float *constants, UINT vector4f_count)
3124 int count = min(vector4f_count, device->d3d_pshader_constantF - start_register);
3126 TRACE("device %p, start_register %u, constants %p, vector4f_count %u.\n",
3127 device, start_register, constants, vector4f_count);
3129 if (!constants || count < 0)
3130 return WINED3DERR_INVALIDCALL;
3132 memcpy(constants, &device->stateBlock->state.ps_consts_f[start_register * 4], count * sizeof(float) * 4);
3137 void CDECL wined3d_device_set_geometry_shader(struct wined3d_device *device, struct wined3d_shader *shader)
3139 struct wined3d_shader *prev = device->updateStateBlock->state.geometry_shader;
3141 TRACE("device %p, shader %p.\n", device, shader);
3144 wined3d_shader_incref(shader);
3146 wined3d_shader_decref(prev);
3148 device->updateStateBlock->state.geometry_shader = shader;
3150 if (device->isRecordingState || shader == prev)
3153 device_invalidate_state(device, STATE_GEOMETRY_SHADER);
3156 struct wined3d_shader * CDECL wined3d_device_get_geometry_shader(const struct wined3d_device *device)
3158 TRACE("device %p.\n", device);
3160 return device->stateBlock->state.geometry_shader;
3163 void CDECL wined3d_device_set_gs_cb(struct wined3d_device *device, UINT idx, struct wined3d_buffer *buffer)
3165 struct wined3d_buffer *prev;
3167 TRACE("device %p, idx %u, buffer %p.\n", device, idx, buffer);
3169 if (idx >= MAX_CONSTANT_BUFFERS)
3171 WARN("Invalid constant buffer index %u.\n", idx);
3175 prev = device->updateStateBlock->state.gs_cb[idx];
3176 device->updateStateBlock->state.gs_cb[idx] = buffer;
3178 if (device->isRecordingState)
3181 wined3d_buffer_incref(buffer);
3183 wined3d_buffer_decref(prev);
3191 InterlockedIncrement(&buffer->resource.bind_count);
3192 wined3d_buffer_incref(buffer);
3196 InterlockedDecrement(&prev->resource.bind_count);
3197 wined3d_buffer_decref(prev);
3202 struct wined3d_buffer * CDECL wined3d_device_get_gs_cb(const struct wined3d_device *device, UINT idx)
3204 TRACE("device %p, idx %u.\n", device, idx);
3206 if (idx >= MAX_CONSTANT_BUFFERS)
3208 WARN("Invalid constant buffer index %u.\n", idx);
3212 return device->stateBlock->state.gs_cb[idx];
3215 void CDECL wined3d_device_set_gs_sampler(struct wined3d_device *device, UINT idx, struct wined3d_sampler *sampler)
3217 struct wined3d_sampler *prev;
3219 TRACE("device %p, idx %u, sampler %p.\n", device, idx, sampler);
3221 if (idx >= MAX_SAMPLER_OBJECTS)
3223 WARN("Invalid sampler index %u.\n", idx);
3227 prev = device->updateStateBlock->state.gs_sampler[idx];
3228 device->updateStateBlock->state.gs_sampler[idx] = sampler;
3231 wined3d_sampler_incref(sampler);
3233 wined3d_sampler_decref(prev);
3236 struct wined3d_sampler * CDECL wined3d_device_get_gs_sampler(const struct wined3d_device *device, UINT idx)
3238 TRACE("device %p, idx %u.\n", device, idx);
3240 if (idx >= MAX_SAMPLER_OBJECTS)
3242 WARN("Invalid sampler index %u.\n", idx);
3246 return device->stateBlock->state.gs_sampler[idx];
3249 /* Context activation is done by the caller. */
3250 /* Do not call while under the GL lock. */
3251 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3252 static HRESULT process_vertices_strided(const struct wined3d_device *device, DWORD dwDestIndex, DWORD dwCount,
3253 const struct wined3d_stream_info *stream_info, struct wined3d_buffer *dest, DWORD flags,
3256 struct wined3d_matrix mat, proj_mat, view_mat, world_mat;
3257 struct wined3d_viewport vp;
3265 if (stream_info->use_map & (1 << WINED3D_FFP_NORMAL))
3267 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3270 if (!(stream_info->use_map & (1 << WINED3D_FFP_POSITION)))
3272 ERR("Source has no position mask\n");
3273 return WINED3DERR_INVALIDCALL;
3276 if (device->stateBlock->state.render_states[WINED3D_RS_CLIPPING])
3278 static BOOL warned = FALSE;
3280 * The clipping code is not quite correct. Some things need
3281 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3282 * so disable clipping for now.
3283 * (The graphics in Half-Life are broken, and my processvertices
3284 * test crashes with IDirect3DDevice3)
3290 FIXME("Clipping is broken and disabled for now\n");
3296 vertex_size = get_flexible_vertex_size(DestFVF);
3297 if (FAILED(hr = wined3d_buffer_map(dest, dwDestIndex * vertex_size, dwCount * vertex_size, &dest_ptr, 0)))
3299 WARN("Failed to map buffer, hr %#x.\n", hr);
3303 wined3d_device_get_transform(device, WINED3D_TS_VIEW, &view_mat);
3304 wined3d_device_get_transform(device, WINED3D_TS_PROJECTION, &proj_mat);
3305 wined3d_device_get_transform(device, WINED3D_TS_WORLD_MATRIX(0), &world_mat);
3307 TRACE("View mat:\n");
3308 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);
3309 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);
3310 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);
3311 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);
3313 TRACE("Proj mat:\n");
3314 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);
3315 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);
3316 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);
3317 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);
3319 TRACE("World mat:\n");
3320 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);
3321 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);
3322 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);
3323 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);
3325 /* Get the viewport */
3326 wined3d_device_get_viewport(device, &vp);
3327 TRACE("viewport x %u, y %u, width %u, height %u, min_z %.8e, max_z %.8e.\n",
3328 vp.x, vp.y, vp.width, vp.height, vp.min_z, vp.max_z);
3330 multiply_matrix(&mat,&view_mat,&world_mat);
3331 multiply_matrix(&mat,&proj_mat,&mat);
3333 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3335 for (i = 0; i < dwCount; i+= 1) {
3336 unsigned int tex_index;
3338 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3339 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3340 /* The position first */
3341 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_POSITION];
3342 const float *p = (const float *)(element->data.addr + i * element->stride);
3344 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3346 /* Multiplication with world, view and projection matrix */
3347 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);
3348 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);
3349 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);
3350 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);
3352 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3354 /* WARNING: The following things are taken from d3d7 and were not yet checked
3355 * against d3d8 or d3d9!
3358 /* Clipping conditions: From msdn
3360 * A vertex is clipped if it does not match the following requirements
3364 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3366 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3367 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3372 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3373 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3376 /* "Normal" viewport transformation (not clipped)
3377 * 1) The values are divided by rhw
3378 * 2) The y axis is negative, so multiply it with -1
3379 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3380 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3381 * 4) Multiply x with Width/2 and add Width/2
3382 * 5) The same for the height
3383 * 6) Add the viewpoint X and Y to the 2D coordinates and
3384 * The minimum Z value to z
3385 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3387 * Well, basically it's simply a linear transformation into viewport
3399 z *= vp.max_z - vp.min_z;
3401 x += vp.width / 2 + vp.x;
3402 y += vp.height / 2 + vp.y;
3407 /* That vertex got clipped
3408 * Contrary to OpenGL it is not dropped completely, it just
3409 * undergoes a different calculation.
3411 TRACE("Vertex got clipped\n");
3418 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3419 * outside of the main vertex buffer memory. That needs some more
3424 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3427 ( (float *) dest_ptr)[0] = x;
3428 ( (float *) dest_ptr)[1] = y;
3429 ( (float *) dest_ptr)[2] = z;
3430 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3432 dest_ptr += 3 * sizeof(float);
3434 if ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW)
3435 dest_ptr += sizeof(float);
3438 if (DestFVF & WINED3DFVF_PSIZE)
3439 dest_ptr += sizeof(DWORD);
3441 if (DestFVF & WINED3DFVF_NORMAL)
3443 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_NORMAL];
3444 const float *normal = (const float *)(element->data.addr + i * element->stride);
3445 /* AFAIK this should go into the lighting information */
3446 FIXME("Didn't expect the destination to have a normal\n");
3447 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3450 if (DestFVF & WINED3DFVF_DIFFUSE)
3452 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_DIFFUSE];
3453 const DWORD *color_d = (const DWORD *)(element->data.addr + i * element->stride);
3454 if (!(stream_info->use_map & (1 << WINED3D_FFP_DIFFUSE)))
3456 static BOOL warned = FALSE;
3459 ERR("No diffuse color in source, but destination has one\n");
3463 *( (DWORD *) dest_ptr) = 0xffffffff;
3464 dest_ptr += sizeof(DWORD);
3468 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3472 if (DestFVF & WINED3DFVF_SPECULAR)
3474 /* What's the color value in the feedback buffer? */
3475 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_SPECULAR];
3476 const DWORD *color_s = (const DWORD *)(element->data.addr + i * element->stride);
3477 if (!(stream_info->use_map & (1 << WINED3D_FFP_SPECULAR)))
3479 static BOOL warned = FALSE;
3482 ERR("No specular color in source, but destination has one\n");
3486 *(DWORD *)dest_ptr = 0xff000000;
3487 dest_ptr += sizeof(DWORD);
3491 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3495 for (tex_index = 0; tex_index < numTextures; ++tex_index)
3497 const struct wined3d_stream_info_element *element = &stream_info->elements[WINED3D_FFP_TEXCOORD0 + tex_index];
3498 const float *tex_coord = (const float *)(element->data.addr + i * element->stride);
3499 if (!(stream_info->use_map & (1 << (WINED3D_FFP_TEXCOORD0 + tex_index))))
3501 ERR("No source texture, but destination requests one\n");
3502 dest_ptr += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3506 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3511 wined3d_buffer_unmap(dest);
3515 #undef copy_and_next
3517 /* Do not call while under the GL lock. */
3518 HRESULT CDECL wined3d_device_process_vertices(struct wined3d_device *device,
3519 UINT src_start_idx, UINT dst_idx, UINT vertex_count, struct wined3d_buffer *dst_buffer,
3520 const struct wined3d_vertex_declaration *declaration, DWORD flags, DWORD dst_fvf)
3522 struct wined3d_state *state = &device->stateBlock->state;
3523 struct wined3d_stream_info stream_info;
3524 const struct wined3d_gl_info *gl_info;
3525 struct wined3d_context *context;
3526 struct wined3d_shader *vs;
3530 TRACE("device %p, src_start_idx %u, dst_idx %u, vertex_count %u, "
3531 "dst_buffer %p, declaration %p, flags %#x, dst_fvf %#x.\n",
3532 device, src_start_idx, dst_idx, vertex_count,
3533 dst_buffer, declaration, flags, dst_fvf);
3536 FIXME("Output vertex declaration not implemented yet.\n");
3538 /* Need any context to write to the vbo. */
3539 context = context_acquire(device, NULL);
3540 gl_info = context->gl_info;
3542 vs = state->vertex_shader;
3543 state->vertex_shader = NULL;
3544 device_stream_info_from_declaration(device, &stream_info);
3545 state->vertex_shader = vs;
3547 /* We can't convert FROM a VBO, and vertex buffers used to source into
3548 * process_vertices() are unlikely to ever be used for drawing. Release
3549 * VBOs in those buffers and fix up the stream_info structure.
3551 * Also apply the start index. */
3552 for (i = 0; i < (sizeof(stream_info.elements) / sizeof(*stream_info.elements)); ++i)
3554 struct wined3d_stream_info_element *e;
3556 if (!(stream_info.use_map & (1 << i)))
3559 e = &stream_info.elements[i];
3560 if (e->data.buffer_object)
3562 struct wined3d_buffer *vb = state->streams[e->stream_idx].buffer;
3563 e->data.buffer_object = 0;
3564 e->data.addr = (BYTE *)((ULONG_PTR)e->data.addr + (ULONG_PTR)buffer_get_sysmem(vb, gl_info));
3565 GL_EXTCALL(glDeleteBuffersARB(1, &vb->buffer_object));
3566 vb->buffer_object = 0;
3569 e->data.addr += e->stride * src_start_idx;
3572 hr = process_vertices_strided(device, dst_idx, vertex_count,
3573 &stream_info, dst_buffer, flags, dst_fvf);
3575 context_release(context);
3580 void CDECL wined3d_device_set_texture_stage_state(struct wined3d_device *device,
3581 UINT stage, enum wined3d_texture_stage_state state, DWORD value)
3583 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3586 TRACE("device %p, stage %u, state %s, value %#x.\n",
3587 device, stage, debug_d3dtexturestate(state), value);
3589 if (state > WINED3D_HIGHEST_TEXTURE_STATE)
3591 WARN("Invalid state %#x passed.\n", state);
3595 if (stage >= gl_info->limits.texture_stages)
3597 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring.\n",
3598 stage, gl_info->limits.texture_stages - 1);
3602 old_value = device->updateStateBlock->state.texture_states[stage][state];
3603 device->updateStateBlock->changed.textureState[stage] |= 1 << state;
3604 device->updateStateBlock->state.texture_states[stage][state] = value;
3606 if (device->isRecordingState)
3608 TRACE("Recording... not performing anything.\n");
3612 /* Checked after the assignments to allow proper stateblock recording. */
3613 if (old_value == value)
3615 TRACE("Application is setting the old value over, nothing to do.\n");
3619 if (stage > device->stateBlock->state.lowest_disabled_stage
3620 && device->StateTable[STATE_TEXTURESTAGE(0, state)].representative
3621 == STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP))
3623 /* Colorop change above lowest disabled stage? That won't change
3624 * anything in the GL setup. Changes in other states are important on
3625 * disabled stages too. */
3629 if (state == WINED3D_TSS_COLOR_OP)
3633 if (value == WINED3D_TOP_DISABLE && old_value != WINED3D_TOP_DISABLE)
3635 /* Previously enabled stage disabled now. Make sure to dirtify
3636 * all enabled stages above stage, they have to be disabled.
3638 * The current stage is dirtified below. */
3639 for (i = stage + 1; i < device->stateBlock->state.lowest_disabled_stage; ++i)
3641 TRACE("Additionally dirtifying stage %u.\n", i);
3642 device_invalidate_state(device, STATE_TEXTURESTAGE(i, WINED3D_TSS_COLOR_OP));
3644 device->stateBlock->state.lowest_disabled_stage = stage;
3645 TRACE("New lowest disabled: %u.\n", stage);
3647 else if (value != WINED3D_TOP_DISABLE && old_value == WINED3D_TOP_DISABLE)
3649 /* Previously disabled stage enabled. Stages above it may need
3650 * enabling. Stage must be lowest_disabled_stage here, if it's
3651 * bigger success is returned above, and stages below the lowest
3652 * disabled stage can't be enabled (because they are enabled
3655 * Again stage stage doesn't need to be dirtified here, it is
3657 for (i = stage + 1; i < gl_info->limits.texture_stages; ++i)
3659 if (device->updateStateBlock->state.texture_states[i][WINED3D_TSS_COLOR_OP] == WINED3D_TOP_DISABLE)
3661 TRACE("Additionally dirtifying stage %u due to enable.\n", i);
3662 device_invalidate_state(device, STATE_TEXTURESTAGE(i, WINED3D_TSS_COLOR_OP));
3664 device->stateBlock->state.lowest_disabled_stage = i;
3665 TRACE("New lowest disabled: %u.\n", i);
3669 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, state));
3672 DWORD CDECL wined3d_device_get_texture_stage_state(const struct wined3d_device *device,
3673 UINT stage, enum wined3d_texture_stage_state state)
3675 TRACE("device %p, stage %u, state %s.\n",
3676 device, stage, debug_d3dtexturestate(state));
3678 if (state > WINED3D_HIGHEST_TEXTURE_STATE)
3680 WARN("Invalid state %#x passed.\n", state);
3684 return device->updateStateBlock->state.texture_states[stage][state];
3687 HRESULT CDECL wined3d_device_set_texture(struct wined3d_device *device,
3688 UINT stage, struct wined3d_texture *texture)
3690 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3691 struct wined3d_texture *prev;
3693 TRACE("device %p, stage %u, texture %p.\n", device, stage, texture);
3695 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3696 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3698 /* Windows accepts overflowing this array... we do not. */
3699 if (stage >= sizeof(device->stateBlock->state.textures) / sizeof(*device->stateBlock->state.textures))
3701 WARN("Ignoring invalid stage %u.\n", stage);
3705 if (texture && texture->resource.pool == WINED3D_POOL_SCRATCH)
3707 WARN("Rejecting attempt to set scratch texture.\n");
3708 return WINED3DERR_INVALIDCALL;
3711 device->updateStateBlock->changed.textures |= 1 << stage;
3713 prev = device->updateStateBlock->state.textures[stage];
3714 TRACE("Previous texture %p.\n", prev);
3716 if (texture == prev)
3718 TRACE("App is setting the same texture again, nothing to do.\n");
3722 TRACE("Setting new texture to %p.\n", texture);
3723 device->updateStateBlock->state.textures[stage] = texture;
3725 if (device->isRecordingState)
3727 TRACE("Recording... not performing anything\n");
3729 if (texture) wined3d_texture_incref(texture);
3730 if (prev) wined3d_texture_decref(prev);
3737 LONG bind_count = InterlockedIncrement(&texture->resource.bind_count);
3739 wined3d_texture_incref(texture);
3741 if (!prev || texture->target != prev->target)
3742 device_invalidate_state(device, STATE_PIXELSHADER);
3744 if (!prev && stage < gl_info->limits.texture_stages)
3746 /* The source arguments for color and alpha ops have different
3747 * meanings when a NULL texture is bound, so the COLOR_OP and
3748 * ALPHA_OP have to be dirtified. */
3749 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_COLOR_OP));
3750 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_ALPHA_OP));
3753 if (bind_count == 1)
3754 texture->sampler = stage;
3759 LONG bind_count = InterlockedDecrement(&prev->resource.bind_count);
3761 if (!texture && stage < gl_info->limits.texture_stages)
3763 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_COLOR_OP));
3764 device_invalidate_state(device, STATE_TEXTURESTAGE(stage, WINED3D_TSS_ALPHA_OP));
3767 if (bind_count && prev->sampler == stage)
3771 /* Search for other stages the texture is bound to. Shouldn't
3772 * happen if applications bind textures to a single stage only. */
3773 TRACE("Searching for other stages the texture is bound to.\n");
3774 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
3776 if (device->updateStateBlock->state.textures[i] == prev)
3778 TRACE("Texture is also bound to stage %u.\n", i);
3785 wined3d_texture_decref(prev);
3788 device_invalidate_state(device, STATE_SAMPLER(stage));
3793 struct wined3d_texture * CDECL wined3d_device_get_texture(const struct wined3d_device *device, UINT stage)
3795 TRACE("device %p, stage %u.\n", device, stage);
3797 if (stage >= WINED3DVERTEXTEXTURESAMPLER0 && stage <= WINED3DVERTEXTEXTURESAMPLER3)
3798 stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3800 if (stage >= sizeof(device->stateBlock->state.textures) / sizeof(*device->stateBlock->state.textures))
3802 WARN("Ignoring invalid stage %u.\n", stage);
3803 return NULL; /* Windows accepts overflowing this array ... we do not. */
3806 return device->stateBlock->state.textures[stage];
3809 HRESULT CDECL wined3d_device_get_back_buffer(const struct wined3d_device *device, UINT swapchain_idx,
3810 UINT backbuffer_idx, enum wined3d_backbuffer_type backbuffer_type, struct wined3d_surface **backbuffer)
3812 struct wined3d_swapchain *swapchain;
3814 TRACE("device %p, swapchain_idx %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
3815 device, swapchain_idx, backbuffer_idx, backbuffer_type, backbuffer);
3817 if (!(swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
3818 return WINED3DERR_INVALIDCALL;
3820 if (!(*backbuffer = wined3d_swapchain_get_back_buffer(swapchain, backbuffer_idx, backbuffer_type)))
3821 return WINED3DERR_INVALIDCALL;
3825 HRESULT CDECL wined3d_device_get_device_caps(const struct wined3d_device *device, WINED3DCAPS *caps)
3827 TRACE("device %p, caps %p.\n", device, caps);
3829 return wined3d_get_device_caps(device->wined3d, device->adapter->ordinal,
3830 device->create_parms.device_type, caps);
3833 HRESULT CDECL wined3d_device_get_display_mode(const struct wined3d_device *device, UINT swapchain_idx,
3834 struct wined3d_display_mode *mode, enum wined3d_display_rotation *rotation)
3836 struct wined3d_swapchain *swapchain;
3838 TRACE("device %p, swapchain_idx %u, mode %p, rotation %p.\n",
3839 device, swapchain_idx, mode, rotation);
3841 if (!(swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
3842 return WINED3DERR_INVALIDCALL;
3844 return wined3d_swapchain_get_display_mode(swapchain, mode, rotation);
3847 HRESULT CDECL wined3d_device_begin_stateblock(struct wined3d_device *device)
3849 struct wined3d_stateblock *stateblock;
3852 TRACE("device %p.\n", device);
3854 if (device->isRecordingState)
3855 return WINED3DERR_INVALIDCALL;
3857 hr = wined3d_stateblock_create(device, WINED3D_SBT_RECORDED, &stateblock);
3861 wined3d_stateblock_decref(device->updateStateBlock);
3862 device->updateStateBlock = stateblock;
3863 device->isRecordingState = TRUE;
3865 TRACE("Recording stateblock %p.\n", stateblock);
3870 HRESULT CDECL wined3d_device_end_stateblock(struct wined3d_device *device,
3871 struct wined3d_stateblock **stateblock)
3873 struct wined3d_stateblock *object = device->updateStateBlock;
3875 TRACE("device %p, stateblock %p.\n", device, stateblock);
3877 if (!device->isRecordingState)
3879 WARN("Not recording.\n");
3881 return WINED3DERR_INVALIDCALL;
3884 stateblock_init_contained_states(object);
3886 *stateblock = object;
3887 device->isRecordingState = FALSE;
3888 device->updateStateBlock = device->stateBlock;
3889 wined3d_stateblock_incref(device->updateStateBlock);
3891 TRACE("Returning stateblock %p.\n", *stateblock);
3896 HRESULT CDECL wined3d_device_begin_scene(struct wined3d_device *device)
3898 /* At the moment we have no need for any functionality at the beginning
3900 TRACE("device %p.\n", device);
3902 if (device->inScene)
3904 WARN("Already in scene, returning WINED3DERR_INVALIDCALL.\n");
3905 return WINED3DERR_INVALIDCALL;
3907 device->inScene = TRUE;
3911 HRESULT CDECL wined3d_device_end_scene(struct wined3d_device *device)
3913 struct wined3d_context *context;
3915 TRACE("device %p.\n", device);
3917 if (!device->inScene)
3919 WARN("Not in scene, returning WINED3DERR_INVALIDCALL.\n");
3920 return WINED3DERR_INVALIDCALL;
3923 context = context_acquire(device, NULL);
3924 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
3925 context->gl_info->gl_ops.gl.p_glFlush();
3926 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
3928 context_release(context);
3930 device->inScene = FALSE;
3934 HRESULT CDECL wined3d_device_present(const struct wined3d_device *device, const RECT *src_rect,
3935 const RECT *dst_rect, HWND dst_window_override, const RGNDATA *dirty_region, DWORD flags)
3939 TRACE("device %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p, flags %#x.\n",
3940 device, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect),
3941 dst_window_override, dirty_region, flags);
3943 for (i = 0; i < device->swapchain_count; ++i)
3945 wined3d_swapchain_present(device->swapchains[i], src_rect,
3946 dst_rect, dst_window_override, dirty_region, flags);
3952 /* Do not call while under the GL lock. */
3953 HRESULT CDECL wined3d_device_clear(struct wined3d_device *device, DWORD rect_count,
3954 const RECT *rects, DWORD flags, const struct wined3d_color *color, float depth, DWORD stencil)
3958 TRACE("device %p, rect_count %u, rects %p, flags %#x, color {%.8e, %.8e, %.8e, %.8e}, depth %.8e, stencil %u.\n",
3959 device, rect_count, rects, flags, color->r, color->g, color->b, color->a, depth, stencil);
3961 if (!rect_count && rects)
3963 WARN("Rects is %p, but rect_count is 0, ignoring clear\n", rects);
3967 if (flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL))
3969 struct wined3d_surface *ds = device->fb.depth_stencil;
3972 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
3973 /* TODO: What about depth stencil buffers without stencil bits? */
3974 return WINED3DERR_INVALIDCALL;
3976 else if (flags & WINED3DCLEAR_TARGET)
3978 if (ds->resource.width < device->fb.render_targets[0]->resource.width
3979 || ds->resource.height < device->fb.render_targets[0]->resource.height)
3981 WARN("Silently ignoring depth and target clear with mismatching sizes\n");
3987 wined3d_get_draw_rect(&device->stateBlock->state, &draw_rect);
3988 device_clear_render_targets(device, device->adapter->gl_info.limits.buffers,
3989 &device->fb, rect_count, rects, &draw_rect, flags, color, depth, stencil);
3994 void CDECL wined3d_device_set_primitive_type(struct wined3d_device *device,
3995 enum wined3d_primitive_type primitive_type)
3997 TRACE("device %p, primitive_type %s\n", device, debug_d3dprimitivetype(primitive_type));
3999 device->updateStateBlock->changed.primitive_type = TRUE;
4000 device->updateStateBlock->state.gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
4003 void CDECL wined3d_device_get_primitive_type(const struct wined3d_device *device,
4004 enum wined3d_primitive_type *primitive_type)
4006 TRACE("device %p, primitive_type %p\n", device, primitive_type);
4008 *primitive_type = d3d_primitive_type_from_gl(device->stateBlock->state.gl_primitive_type);
4010 TRACE("Returning %s\n", debug_d3dprimitivetype(*primitive_type));
4013 HRESULT CDECL wined3d_device_draw_primitive(struct wined3d_device *device, UINT start_vertex, UINT vertex_count)
4015 TRACE("device %p, start_vertex %u, vertex_count %u.\n", device, start_vertex, vertex_count);
4017 if (!device->stateBlock->state.vertex_declaration)
4019 WARN("Called without a valid vertex declaration set.\n");
4020 return WINED3DERR_INVALIDCALL;
4023 if (device->stateBlock->state.load_base_vertex_index)
4025 device->stateBlock->state.load_base_vertex_index = 0;
4026 device_invalidate_state(device, STATE_BASEVERTEXINDEX);
4029 /* Account for the loading offset due to index buffers. Instead of
4030 * reloading all sources correct it with the startvertex parameter. */
4031 draw_primitive(device, start_vertex, vertex_count, 0, 0, FALSE);
4035 HRESULT CDECL wined3d_device_draw_indexed_primitive(struct wined3d_device *device, UINT start_idx, UINT index_count)
4037 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4039 TRACE("device %p, start_idx %u, index_count %u.\n", device, start_idx, index_count);
4041 if (!device->stateBlock->state.index_buffer)
4043 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4044 * without an index buffer set. (The first time at least...)
4045 * D3D8 simply dies, but I doubt it can do much harm to return
4046 * D3DERR_INVALIDCALL there as well. */
4047 WARN("Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL.\n");
4048 return WINED3DERR_INVALIDCALL;
4051 if (!device->stateBlock->state.vertex_declaration)
4053 WARN("Called without a valid vertex declaration set.\n");
4054 return WINED3DERR_INVALIDCALL;
4057 if (!gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX] &&
4058 device->stateBlock->state.load_base_vertex_index != device->stateBlock->state.base_vertex_index)
4060 device->stateBlock->state.load_base_vertex_index = device->stateBlock->state.base_vertex_index;
4061 device_invalidate_state(device, STATE_BASEVERTEXINDEX);
4064 draw_primitive(device, start_idx, index_count, 0, 0, TRUE);
4069 void CDECL wined3d_device_draw_indexed_primitive_instanced(struct wined3d_device *device,
4070 UINT start_idx, UINT index_count, UINT start_instance, UINT instance_count)
4072 TRACE("device %p, start_idx %u, index_count %u.\n", device, start_idx, index_count);
4074 draw_primitive(device, start_idx, index_count, start_instance, instance_count, TRUE);
4077 /* This is a helper function for UpdateTexture, there is no UpdateVolume method in D3D. */
4078 static HRESULT device_update_volume(struct wined3d_device *device,
4079 struct wined3d_volume *src_volume, struct wined3d_volume *dst_volume)
4081 struct wined3d_map_desc src;
4082 struct wined3d_map_desc dst;
4085 TRACE("device %p, src_volume %p, dst_volume %p.\n",
4086 device, src_volume, dst_volume);
4088 /* TODO: Implement direct loading into the gl volume instead of using
4089 * memcpy and dirtification to improve loading performance. */
4090 if (FAILED(hr = wined3d_volume_map(src_volume, &src, NULL, WINED3D_MAP_READONLY)))
4092 if (FAILED(hr = wined3d_volume_map(dst_volume, &dst, NULL, WINED3D_MAP_DISCARD)))
4094 wined3d_volume_unmap(src_volume);
4098 memcpy(dst.data, src.data, dst_volume->resource.size);
4100 hr = wined3d_volume_unmap(dst_volume);
4102 wined3d_volume_unmap(src_volume);
4104 hr = wined3d_volume_unmap(src_volume);
4109 HRESULT CDECL wined3d_device_update_texture(struct wined3d_device *device,
4110 struct wined3d_texture *src_texture, struct wined3d_texture *dst_texture)
4112 enum wined3d_resource_type type;
4113 unsigned int level_count, i;
4116 TRACE("device %p, src_texture %p, dst_texture %p.\n", device, src_texture, dst_texture);
4118 /* Verify that the source and destination textures are non-NULL. */
4119 if (!src_texture || !dst_texture)
4121 WARN("Source and destination textures must be non-NULL, returning WINED3DERR_INVALIDCALL.\n");
4122 return WINED3DERR_INVALIDCALL;
4125 if (src_texture == dst_texture)
4127 WARN("Source and destination are the same object, returning WINED3DERR_INVALIDCALL.\n");
4128 return WINED3DERR_INVALIDCALL;
4131 /* Verify that the source and destination textures are the same type. */
4132 type = src_texture->resource.type;
4133 if (dst_texture->resource.type != type)
4135 WARN("Source and destination have different types, returning WINED3DERR_INVALIDCALL.\n");
4136 return WINED3DERR_INVALIDCALL;
4139 /* Check that both textures have the identical numbers of levels. */
4140 level_count = wined3d_texture_get_level_count(src_texture);
4141 if (wined3d_texture_get_level_count(dst_texture) != level_count)
4143 WARN("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
4144 return WINED3DERR_INVALIDCALL;
4147 /* Make sure that the destination texture is loaded. */
4148 dst_texture->texture_ops->texture_preload(dst_texture, SRGB_RGB);
4150 /* Update every surface level of the texture. */
4153 case WINED3D_RTYPE_TEXTURE:
4155 struct wined3d_surface *src_surface;
4156 struct wined3d_surface *dst_surface;
4158 for (i = 0; i < level_count; ++i)
4160 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture, i));
4161 dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture, i));
4162 hr = wined3d_device_update_surface(device, src_surface, NULL, dst_surface, NULL);
4165 WARN("Failed to update surface, hr %#x.\n", hr);
4172 case WINED3D_RTYPE_CUBE_TEXTURE:
4174 struct wined3d_surface *src_surface;
4175 struct wined3d_surface *dst_surface;
4177 for (i = 0; i < level_count * 6; ++i)
4179 src_surface = surface_from_resource(wined3d_texture_get_sub_resource(src_texture, i));
4180 dst_surface = surface_from_resource(wined3d_texture_get_sub_resource(dst_texture, i));
4181 hr = wined3d_device_update_surface(device, src_surface, NULL, dst_surface, NULL);
4184 WARN("Failed to update surface, hr %#x.\n", hr);
4191 case WINED3D_RTYPE_VOLUME_TEXTURE:
4193 for (i = 0; i < level_count; ++i)
4195 hr = device_update_volume(device,
4196 volume_from_resource(wined3d_texture_get_sub_resource(src_texture, i)),
4197 volume_from_resource(wined3d_texture_get_sub_resource(dst_texture, i)));
4200 WARN("Failed to update volume, hr %#x.\n", hr);
4208 FIXME("Unsupported texture type %#x.\n", type);
4209 return WINED3DERR_INVALIDCALL;
4215 HRESULT CDECL wined3d_device_get_front_buffer_data(const struct wined3d_device *device,
4216 UINT swapchain_idx, struct wined3d_surface *dst_surface)
4218 struct wined3d_swapchain *swapchain;
4220 TRACE("device %p, swapchain_idx %u, dst_surface %p.\n", device, swapchain_idx, dst_surface);
4222 if (!(swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
4223 return WINED3DERR_INVALIDCALL;
4225 return wined3d_swapchain_get_front_buffer_data(swapchain, dst_surface);
4228 HRESULT CDECL wined3d_device_validate_device(const struct wined3d_device *device, DWORD *num_passes)
4230 const struct wined3d_state *state = &device->stateBlock->state;
4231 struct wined3d_texture *texture;
4234 TRACE("device %p, num_passes %p.\n", device, num_passes);
4236 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
4238 if (state->sampler_states[i][WINED3D_SAMP_MIN_FILTER] == WINED3D_TEXF_NONE)
4240 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4241 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4243 if (state->sampler_states[i][WINED3D_SAMP_MAG_FILTER] == WINED3D_TEXF_NONE)
4245 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
4246 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
4249 texture = state->textures[i];
4250 if (!texture || texture->resource.format->flags & WINED3DFMT_FLAG_FILTERING) continue;
4252 if (state->sampler_states[i][WINED3D_SAMP_MAG_FILTER] != WINED3D_TEXF_POINT)
4254 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
4257 if (state->sampler_states[i][WINED3D_SAMP_MIN_FILTER] != WINED3D_TEXF_POINT)
4259 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
4262 if (state->sampler_states[i][WINED3D_SAMP_MIP_FILTER] != WINED3D_TEXF_NONE
4263 && state->sampler_states[i][WINED3D_SAMP_MIP_FILTER] != WINED3D_TEXF_POINT)
4265 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
4270 if (state->render_states[WINED3D_RS_ZENABLE] || state->render_states[WINED3D_RS_ZWRITEENABLE]
4271 || state->render_states[WINED3D_RS_STENCILENABLE])
4273 struct wined3d_surface *ds = device->fb.depth_stencil;
4274 struct wined3d_surface *target = device->fb.render_targets[0];
4277 && (ds->resource.width < target->resource.width || ds->resource.height < target->resource.height))
4279 WARN("Depth stencil is smaller than the color buffer, returning D3DERR_CONFLICTINGRENDERSTATE\n");
4280 return WINED3DERR_CONFLICTINGRENDERSTATE;
4284 /* return a sensible default */
4287 TRACE("returning D3D_OK\n");
4291 void CDECL wined3d_device_set_software_vertex_processing(struct wined3d_device *device, BOOL software)
4295 TRACE("device %p, software %#x.\n", device, software);
4299 FIXME("device %p, software %#x stub!\n", device, software);
4303 device->softwareVertexProcessing = software;
4306 BOOL CDECL wined3d_device_get_software_vertex_processing(const struct wined3d_device *device)
4310 TRACE("device %p.\n", device);
4314 TRACE("device %p stub!\n", device);
4318 return device->softwareVertexProcessing;
4321 HRESULT CDECL wined3d_device_get_raster_status(const struct wined3d_device *device,
4322 UINT swapchain_idx, struct wined3d_raster_status *raster_status)
4324 struct wined3d_swapchain *swapchain;
4326 TRACE("device %p, swapchain_idx %u, raster_status %p.\n",
4327 device, swapchain_idx, raster_status);
4329 if (!(swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
4330 return WINED3DERR_INVALIDCALL;
4332 return wined3d_swapchain_get_raster_status(swapchain, raster_status);
4335 HRESULT CDECL wined3d_device_set_npatch_mode(struct wined3d_device *device, float segments)
4339 TRACE("device %p, segments %.8e.\n", device, segments);
4341 if (segments != 0.0f)
4345 FIXME("device %p, segments %.8e stub!\n", device, segments);
4353 float CDECL wined3d_device_get_npatch_mode(const struct wined3d_device *device)
4357 TRACE("device %p.\n", device);
4361 FIXME("device %p stub!\n", device);
4368 HRESULT CDECL wined3d_device_update_surface(struct wined3d_device *device,
4369 struct wined3d_surface *src_surface, const RECT *src_rect,
4370 struct wined3d_surface *dst_surface, const POINT *dst_point)
4372 TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_point %s.\n",
4373 device, src_surface, wine_dbgstr_rect(src_rect),
4374 dst_surface, wine_dbgstr_point(dst_point));
4376 if (src_surface->resource.pool != WINED3D_POOL_SYSTEM_MEM || dst_surface->resource.pool != WINED3D_POOL_DEFAULT)
4378 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n",
4379 src_surface, dst_surface);
4380 return WINED3DERR_INVALIDCALL;
4383 return surface_upload_from_surface(dst_surface, dst_point, src_surface, src_rect);
4386 /* Do not call while under the GL lock. */
4387 HRESULT CDECL wined3d_device_color_fill(struct wined3d_device *device,
4388 struct wined3d_surface *surface, const RECT *rect, const struct wined3d_color *color)
4392 TRACE("device %p, surface %p, rect %s, color {%.8e, %.8e, %.8e, %.8e}.\n",
4393 device, surface, wine_dbgstr_rect(rect),
4394 color->r, color->g, color->b, color->a);
4396 if (surface->resource.pool != WINED3D_POOL_DEFAULT && surface->resource.pool != WINED3D_POOL_SYSTEM_MEM)
4398 WARN("Color-fill not allowed on %s surfaces.\n", debug_d3dpool(surface->resource.pool));
4399 return WINED3DERR_INVALIDCALL;
4404 SetRect(&r, 0, 0, surface->resource.width, surface->resource.height);
4408 return surface_color_fill(surface, rect, color);
4411 /* Do not call while under the GL lock. */
4412 void CDECL wined3d_device_clear_rendertarget_view(struct wined3d_device *device,
4413 struct wined3d_rendertarget_view *rendertarget_view, const struct wined3d_color *color)
4415 struct wined3d_resource *resource;
4419 resource = rendertarget_view->resource;
4420 if (resource->type != WINED3D_RTYPE_SURFACE)
4422 FIXME("Only supported on surface resources\n");
4426 SetRect(&rect, 0, 0, resource->width, resource->height);
4427 hr = surface_color_fill(surface_from_resource(resource), &rect, color);
4428 if (FAILED(hr)) ERR("Color fill failed, hr %#x.\n", hr);
4431 struct wined3d_surface * CDECL wined3d_device_get_render_target(const struct wined3d_device *device,
4432 UINT render_target_idx)
4434 TRACE("device %p, render_target_idx %u.\n", device, render_target_idx);
4436 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
4438 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
4442 return device->fb.render_targets[render_target_idx];
4445 struct wined3d_surface * CDECL wined3d_device_get_depth_stencil(const struct wined3d_device *device)
4447 TRACE("device %p.\n", device);
4449 return device->fb.depth_stencil;
4452 HRESULT CDECL wined3d_device_set_render_target(struct wined3d_device *device,
4453 UINT render_target_idx, struct wined3d_surface *render_target, BOOL set_viewport)
4455 struct wined3d_surface *prev;
4457 TRACE("device %p, render_target_idx %u, render_target %p, set_viewport %#x.\n",
4458 device, render_target_idx, render_target, set_viewport);
4460 if (render_target_idx >= device->adapter->gl_info.limits.buffers)
4462 WARN("Only %u render targets are supported.\n", device->adapter->gl_info.limits.buffers);
4463 return WINED3DERR_INVALIDCALL;
4466 /* Render target 0 can't be set to NULL. */
4467 if (!render_target && !render_target_idx)
4469 WARN("Trying to set render target 0 to NULL.\n");
4470 return WINED3DERR_INVALIDCALL;
4473 if (render_target && !(render_target->resource.usage & WINED3DUSAGE_RENDERTARGET))
4475 FIXME("Surface %p doesn't have render target usage.\n", render_target);
4476 return WINED3DERR_INVALIDCALL;
4479 /* Set the viewport and scissor rectangles, if requested. Tests show that
4480 * stateblock recording is ignored, the change goes directly into the
4481 * primary stateblock. */
4482 if (!render_target_idx && set_viewport)
4484 struct wined3d_state *state = &device->stateBlock->state;
4486 state->viewport.x = 0;
4487 state->viewport.y = 0;
4488 state->viewport.width = render_target->resource.width;
4489 state->viewport.height = render_target->resource.height;
4490 state->viewport.min_z = 0.0f;
4491 state->viewport.max_z = 1.0f;
4492 device_invalidate_state(device, STATE_VIEWPORT);
4494 state->scissor_rect.top = 0;
4495 state->scissor_rect.left = 0;
4496 state->scissor_rect.right = render_target->resource.width;
4497 state->scissor_rect.bottom = render_target->resource.height;
4498 device_invalidate_state(device, STATE_SCISSORRECT);
4502 prev = device->fb.render_targets[render_target_idx];
4503 if (render_target == prev)
4507 wined3d_surface_incref(render_target);
4508 device->fb.render_targets[render_target_idx] = render_target;
4509 /* Release after the assignment, to prevent device_resource_released()
4510 * from seeing the surface as still in use. */
4512 wined3d_surface_decref(prev);
4514 device_invalidate_state(device, STATE_FRAMEBUFFER);
4519 void CDECL wined3d_device_set_depth_stencil(struct wined3d_device *device, struct wined3d_surface *depth_stencil)
4521 struct wined3d_surface *prev = device->fb.depth_stencil;
4523 TRACE("device %p, depth_stencil %p, old depth_stencil %p.\n",
4524 device, depth_stencil, prev);
4526 if (prev == depth_stencil)
4528 TRACE("Trying to do a NOP SetRenderTarget operation.\n");
4534 if (device->swapchains[0]->desc.flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
4535 || prev->flags & SFLAG_DISCARD)
4537 surface_modify_ds_location(prev, SFLAG_DISCARDED,
4538 prev->resource.width, prev->resource.height);
4539 if (prev == device->onscreen_depth_stencil)
4541 wined3d_surface_decref(device->onscreen_depth_stencil);
4542 device->onscreen_depth_stencil = NULL;
4547 device->fb.depth_stencil = depth_stencil;
4549 wined3d_surface_incref(depth_stencil);
4551 if (!prev != !depth_stencil)
4553 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
4554 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_ZENABLE));
4555 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILENABLE));
4556 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
4557 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
4559 else if (prev && prev->resource.format->depth_size != depth_stencil->resource.format->depth_size)
4561 device_invalidate_state(device, STATE_RENDER(WINED3D_RS_DEPTHBIAS));
4564 wined3d_surface_decref(prev);
4566 device_invalidate_state(device, STATE_FRAMEBUFFER);
4571 HRESULT CDECL wined3d_device_set_cursor_properties(struct wined3d_device *device,
4572 UINT x_hotspot, UINT y_hotspot, struct wined3d_surface *cursor_image)
4574 TRACE("device %p, x_hotspot %u, y_hotspot %u, cursor_image %p.\n",
4575 device, x_hotspot, y_hotspot, cursor_image);
4577 /* some basic validation checks */
4578 if (device->cursorTexture)
4580 struct wined3d_context *context = context_acquire(device, NULL);
4581 context->gl_info->gl_ops.gl.p_glDeleteTextures(1, &device->cursorTexture);
4582 context_release(context);
4583 device->cursorTexture = 0;
4588 struct wined3d_display_mode mode;
4589 struct wined3d_map_desc map_desc;
4592 /* MSDN: Cursor must be A8R8G8B8 */
4593 if (cursor_image->resource.format->id != WINED3DFMT_B8G8R8A8_UNORM)
4595 WARN("surface %p has an invalid format.\n", cursor_image);
4596 return WINED3DERR_INVALIDCALL;
4599 if (FAILED(hr = wined3d_get_adapter_display_mode(device->wined3d, device->adapter->ordinal, &mode, NULL)))
4601 ERR("Failed to get display mode, hr %#x.\n", hr);
4602 return WINED3DERR_INVALIDCALL;
4605 /* MSDN: Cursor must be smaller than the display mode */
4606 if (cursor_image->resource.width > mode.width || cursor_image->resource.height > mode.height)
4608 WARN("Surface %p dimensions are %ux%u, but screen dimensions are %ux%u.\n",
4609 cursor_image, cursor_image->resource.width, cursor_image->resource.height,
4610 mode.width, mode.height);
4611 return WINED3DERR_INVALIDCALL;
4614 /* TODO: MSDN: Cursor sizes must be a power of 2 */
4616 /* Do not store the surface's pointer because the application may
4617 * release it after setting the cursor image. Windows doesn't
4618 * addref the set surface, so we can't do this either without
4619 * creating circular refcount dependencies. Copy out the gl texture
4621 device->cursorWidth = cursor_image->resource.width;
4622 device->cursorHeight = cursor_image->resource.height;
4623 if (SUCCEEDED(wined3d_surface_map(cursor_image, &map_desc, NULL, WINED3D_MAP_READONLY)))
4625 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4626 const struct wined3d_format *format = wined3d_get_format(gl_info, WINED3DFMT_B8G8R8A8_UNORM);
4627 struct wined3d_context *context;
4628 char *mem, *bits = map_desc.data;
4629 GLint intfmt = format->glInternal;
4630 GLint gl_format = format->glFormat;
4631 GLint type = format->glType;
4632 INT height = device->cursorHeight;
4633 INT width = device->cursorWidth;
4634 INT bpp = format->byte_count;
4637 /* Reformat the texture memory (pitch and width can be
4639 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
4640 for (i = 0; i < height; ++i)
4641 memcpy(&mem[width * bpp * i], &bits[map_desc.row_pitch * i], width * bpp);
4642 wined3d_surface_unmap(cursor_image);
4644 context = context_acquire(device, NULL);
4646 if (gl_info->supported[APPLE_CLIENT_STORAGE])
4648 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
4649 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
4652 invalidate_active_texture(device, context);
4653 /* Create a new cursor texture */
4654 gl_info->gl_ops.gl.p_glGenTextures(1, &device->cursorTexture);
4655 checkGLcall("glGenTextures");
4656 context_bind_texture(context, GL_TEXTURE_2D, device->cursorTexture);
4657 /* Copy the bitmap memory into the cursor texture */
4658 gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, gl_format, type, mem);
4659 checkGLcall("glTexImage2D");
4660 HeapFree(GetProcessHeap(), 0, mem);
4662 if (gl_info->supported[APPLE_CLIENT_STORAGE])
4664 gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
4665 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
4668 context_release(context);
4672 FIXME("A cursor texture was not returned.\n");
4673 device->cursorTexture = 0;
4676 if (cursor_image->resource.width == 32 && cursor_image->resource.height == 32)
4678 UINT mask_size = cursor_image->resource.width * cursor_image->resource.height / 8;
4679 ICONINFO cursorInfo;
4683 /* 32-bit user32 cursors ignore the alpha channel if it's all
4684 * zeroes, and use the mask instead. Fill the mask with all ones
4685 * to ensure we still get a fully transparent cursor. */
4686 maskBits = HeapAlloc(GetProcessHeap(), 0, mask_size);
4687 memset(maskBits, 0xff, mask_size);
4688 wined3d_surface_map(cursor_image, &map_desc, NULL,
4689 WINED3D_MAP_NO_DIRTY_UPDATE | WINED3D_MAP_READONLY);
4690 TRACE("width: %u height: %u.\n", cursor_image->resource.width, cursor_image->resource.height);
4692 cursorInfo.fIcon = FALSE;
4693 cursorInfo.xHotspot = x_hotspot;
4694 cursorInfo.yHotspot = y_hotspot;
4695 cursorInfo.hbmMask = CreateBitmap(cursor_image->resource.width, cursor_image->resource.height,
4697 cursorInfo.hbmColor = CreateBitmap(cursor_image->resource.width, cursor_image->resource.height,
4698 1, 32, map_desc.data);
4699 wined3d_surface_unmap(cursor_image);
4700 /* Create our cursor and clean up. */
4701 cursor = CreateIconIndirect(&cursorInfo);
4702 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
4703 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
4704 if (device->hardwareCursor) DestroyCursor(device->hardwareCursor);
4705 device->hardwareCursor = cursor;
4706 if (device->bCursorVisible) SetCursor( cursor );
4707 HeapFree(GetProcessHeap(), 0, maskBits);
4711 device->xHotSpot = x_hotspot;
4712 device->yHotSpot = y_hotspot;
4716 void CDECL wined3d_device_set_cursor_position(struct wined3d_device *device,
4717 int x_screen_space, int y_screen_space, DWORD flags)
4719 TRACE("device %p, x %d, y %d, flags %#x.\n",
4720 device, x_screen_space, y_screen_space, flags);
4722 device->xScreenSpace = x_screen_space;
4723 device->yScreenSpace = y_screen_space;
4725 if (device->hardwareCursor)
4729 GetCursorPos( &pt );
4730 if (x_screen_space == pt.x && y_screen_space == pt.y)
4732 SetCursorPos( x_screen_space, y_screen_space );
4734 /* Switch to the software cursor if position diverges from the hardware one. */
4735 GetCursorPos( &pt );
4736 if (x_screen_space != pt.x || y_screen_space != pt.y)
4738 if (device->bCursorVisible) SetCursor( NULL );
4739 DestroyCursor( device->hardwareCursor );
4740 device->hardwareCursor = 0;
4745 BOOL CDECL wined3d_device_show_cursor(struct wined3d_device *device, BOOL show)
4747 BOOL oldVisible = device->bCursorVisible;
4749 TRACE("device %p, show %#x.\n", device, show);
4752 * When ShowCursor is first called it should make the cursor appear at the OS's last
4753 * known cursor position.
4755 if (show && !oldVisible)
4759 device->xScreenSpace = pt.x;
4760 device->yScreenSpace = pt.y;
4763 if (device->hardwareCursor)
4765 device->bCursorVisible = show;
4767 SetCursor(device->hardwareCursor);
4773 if (device->cursorTexture)
4774 device->bCursorVisible = show;
4780 void CDECL wined3d_device_evict_managed_resources(struct wined3d_device *device)
4782 struct wined3d_resource *resource, *cursor;
4784 TRACE("device %p.\n", device);
4786 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
4788 TRACE("Checking resource %p for eviction.\n", resource);
4790 if (resource->pool == WINED3D_POOL_MANAGED && !resource->map_count)
4792 TRACE("Evicting %p.\n", resource);
4793 resource->resource_ops->resource_unload(resource);
4797 /* Invalidate stream sources, the buffer(s) may have been evicted. */
4798 device_invalidate_state(device, STATE_STREAMSRC);
4801 /* Do not call while under the GL lock. */
4802 static void delete_opengl_contexts(struct wined3d_device *device, struct wined3d_swapchain *swapchain)
4804 struct wined3d_resource *resource, *cursor;
4805 const struct wined3d_gl_info *gl_info;
4806 struct wined3d_context *context;
4807 struct wined3d_shader *shader;
4809 context = context_acquire(device, NULL);
4810 gl_info = context->gl_info;
4812 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
4814 TRACE("Unloading resource %p.\n", resource);
4816 resource->resource_ops->resource_unload(resource);
4819 LIST_FOR_EACH_ENTRY(shader, &device->shaders, struct wined3d_shader, shader_list_entry)
4821 device->shader_backend->shader_destroy(shader);
4824 if (device->depth_blt_texture)
4826 gl_info->gl_ops.gl.p_glDeleteTextures(1, &device->depth_blt_texture);
4827 device->depth_blt_texture = 0;
4829 if (device->cursorTexture)
4831 gl_info->gl_ops.gl.p_glDeleteTextures(1, &device->cursorTexture);
4832 device->cursorTexture = 0;
4835 device->blitter->free_private(device);
4836 device->shader_backend->shader_free_private(device);
4837 destroy_dummy_textures(device, gl_info);
4839 context_release(context);
4841 while (device->context_count)
4843 swapchain_destroy_contexts(device->contexts[0]->swapchain);
4846 HeapFree(GetProcessHeap(), 0, swapchain->context);
4847 swapchain->context = NULL;
4850 /* Do not call while under the GL lock. */
4851 static HRESULT create_primary_opengl_context(struct wined3d_device *device, struct wined3d_swapchain *swapchain)
4853 struct wined3d_context *context;
4854 struct wined3d_surface *target;
4857 if (FAILED(hr = device->shader_backend->shader_alloc_private(device, device->adapter->fragment_pipe)))
4859 ERR("Failed to allocate shader private data, hr %#x.\n", hr);
4863 if (FAILED(hr = device->blitter->alloc_private(device)))
4865 ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
4866 device->shader_backend->shader_free_private(device);
4870 /* Recreate the primary swapchain's context */
4871 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
4872 if (!swapchain->context)
4874 ERR("Failed to allocate memory for swapchain context array.\n");
4875 device->blitter->free_private(device);
4876 device->shader_backend->shader_free_private(device);
4877 return E_OUTOFMEMORY;
4880 target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
4881 if (!(context = context_create(swapchain, target, swapchain->ds_format)))
4883 WARN("Failed to create context.\n");
4884 device->blitter->free_private(device);
4885 device->shader_backend->shader_free_private(device);
4886 HeapFree(GetProcessHeap(), 0, swapchain->context);
4890 swapchain->context[0] = context;
4891 swapchain->num_contexts = 1;
4892 create_dummy_textures(device, context);
4893 context_release(context);
4898 /* Do not call while under the GL lock. */
4899 HRESULT CDECL wined3d_device_reset(struct wined3d_device *device,
4900 const struct wined3d_swapchain_desc *swapchain_desc, const struct wined3d_display_mode *mode,
4901 wined3d_device_reset_cb callback, BOOL reset_state)
4903 struct wined3d_resource *resource, *cursor;
4904 struct wined3d_swapchain *swapchain;
4905 struct wined3d_display_mode m;
4906 BOOL DisplayModeChanged = FALSE;
4907 BOOL update_desc = FALSE;
4908 UINT backbuffer_width = swapchain_desc->backbuffer_width;
4909 UINT backbuffer_height = swapchain_desc->backbuffer_height;
4910 HRESULT hr = WINED3D_OK;
4913 TRACE("device %p, swapchain_desc %p, mode %p, callback %p.\n", device, swapchain_desc, mode, callback);
4915 if (!(swapchain = wined3d_device_get_swapchain(device, 0)))
4917 ERR("Failed to get the first implicit swapchain.\n");
4918 return WINED3DERR_INVALIDCALL;
4922 stateblock_unbind_resources(device->stateBlock);
4924 if (device->fb.render_targets)
4926 if (swapchain->back_buffers && swapchain->back_buffers[0])
4927 wined3d_device_set_render_target(device, 0, swapchain->back_buffers[0], FALSE);
4929 wined3d_device_set_render_target(device, 0, swapchain->front_buffer, FALSE);
4930 for (i = 1; i < device->adapter->gl_info.limits.buffers; ++i)
4932 wined3d_device_set_render_target(device, i, NULL, FALSE);
4935 wined3d_device_set_depth_stencil(device, NULL);
4937 if (device->onscreen_depth_stencil)
4939 wined3d_surface_decref(device->onscreen_depth_stencil);
4940 device->onscreen_depth_stencil = NULL;
4945 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &device->resources, struct wined3d_resource, resource_list_entry)
4947 TRACE("Enumerating resource %p.\n", resource);
4948 if (FAILED(hr = callback(resource)))
4953 /* Is it necessary to recreate the gl context? Actually every setting can be changed
4954 * on an existing gl context, so there's no real need for recreation.
4956 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
4958 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
4960 TRACE("New params:\n");
4961 TRACE("backbuffer_width %u\n", swapchain_desc->backbuffer_width);
4962 TRACE("backbuffer_height %u\n", swapchain_desc->backbuffer_height);
4963 TRACE("backbuffer_format %s\n", debug_d3dformat(swapchain_desc->backbuffer_format));
4964 TRACE("backbuffer_count %u\n", swapchain_desc->backbuffer_count);
4965 TRACE("multisample_type %#x\n", swapchain_desc->multisample_type);
4966 TRACE("multisample_quality %u\n", swapchain_desc->multisample_quality);
4967 TRACE("swap_effect %#x\n", swapchain_desc->swap_effect);
4968 TRACE("device_window %p\n", swapchain_desc->device_window);
4969 TRACE("windowed %#x\n", swapchain_desc->windowed);
4970 TRACE("enable_auto_depth_stencil %#x\n", swapchain_desc->enable_auto_depth_stencil);
4971 if (swapchain_desc->enable_auto_depth_stencil)
4972 TRACE("auto_depth_stencil_format %s\n", debug_d3dformat(swapchain_desc->auto_depth_stencil_format));
4973 TRACE("flags %#x\n", swapchain_desc->flags);
4974 TRACE("refresh_rate %u\n", swapchain_desc->refresh_rate);
4975 TRACE("swap_interval %u\n", swapchain_desc->swap_interval);
4976 TRACE("auto_restore_display_mode %#x\n", swapchain_desc->auto_restore_display_mode);
4978 /* No special treatment of these parameters. Just store them */
4979 swapchain->desc.swap_effect = swapchain_desc->swap_effect;
4980 swapchain->desc.flags = swapchain_desc->flags;
4981 swapchain->desc.swap_interval = swapchain_desc->swap_interval;
4982 swapchain->desc.refresh_rate = swapchain_desc->refresh_rate;
4984 /* What to do about these? */
4985 if (swapchain_desc->backbuffer_count
4986 && swapchain_desc->backbuffer_count != swapchain->desc.backbuffer_count)
4987 FIXME("Cannot change the back buffer count yet.\n");
4989 if (swapchain_desc->device_window
4990 && swapchain_desc->device_window != swapchain->desc.device_window)
4992 TRACE("Changing the device window from %p to %p.\n",
4993 swapchain->desc.device_window, swapchain_desc->device_window);
4994 swapchain->desc.device_window = swapchain_desc->device_window;
4995 swapchain->device_window = swapchain_desc->device_window;
4996 wined3d_swapchain_set_window(swapchain, NULL);
4999 if (swapchain_desc->enable_auto_depth_stencil && !device->auto_depth_stencil)
5001 TRACE("Creating the depth stencil buffer\n");
5003 if (FAILED(hr = device->device_parent->ops->create_swapchain_surface(device->device_parent,
5004 device->device_parent, swapchain_desc->backbuffer_width, swapchain_desc->backbuffer_height,
5005 swapchain_desc->auto_depth_stencil_format, WINED3DUSAGE_DEPTHSTENCIL,
5006 swapchain_desc->multisample_type, swapchain_desc->multisample_quality,
5007 &device->auto_depth_stencil)))
5009 ERR("Failed to create the depth stencil buffer, hr %#x.\n", hr);
5010 return WINED3DERR_INVALIDCALL;
5014 /* Reset the depth stencil */
5015 if (swapchain_desc->enable_auto_depth_stencil)
5016 wined3d_device_set_depth_stencil(device, device->auto_depth_stencil);
5020 DisplayModeChanged = TRUE;
5023 else if (swapchain_desc->windowed)
5025 m.width = swapchain->orig_width;
5026 m.height = swapchain->orig_height;
5028 m.format_id = swapchain->desc.backbuffer_format;
5029 m.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN;
5033 m.width = swapchain_desc->backbuffer_width;
5034 m.height = swapchain_desc->backbuffer_height;
5035 m.refresh_rate = swapchain_desc->refresh_rate;
5036 m.format_id = swapchain_desc->backbuffer_format;
5037 m.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN;
5040 if (!backbuffer_width || !backbuffer_height)
5042 /* The application is requesting that either the swapchain width or
5043 * height be set to the corresponding dimension in the window's
5048 if (!swapchain_desc->windowed)
5049 return WINED3DERR_INVALIDCALL;
5051 if (!GetClientRect(swapchain->device_window, &client_rect))
5053 ERR("Failed to get client rect, last error %#x.\n", GetLastError());
5054 return WINED3DERR_INVALIDCALL;
5057 if (!backbuffer_width)
5058 backbuffer_width = client_rect.right;
5060 if (!backbuffer_height)
5061 backbuffer_height = client_rect.bottom;
5064 if (backbuffer_width != swapchain->desc.backbuffer_width
5065 || backbuffer_height != swapchain->desc.backbuffer_height)
5067 if (!swapchain_desc->windowed)
5068 DisplayModeChanged = TRUE;
5070 swapchain->desc.backbuffer_width = backbuffer_width;
5071 swapchain->desc.backbuffer_height = backbuffer_height;
5075 if (swapchain_desc->backbuffer_format != WINED3DFMT_UNKNOWN
5076 && swapchain_desc->backbuffer_format != swapchain->desc.backbuffer_format)
5078 swapchain->desc.backbuffer_format = swapchain_desc->backbuffer_format;
5082 if (swapchain_desc->multisample_type != swapchain->desc.multisample_type
5083 || swapchain_desc->multisample_quality != swapchain->desc.multisample_quality)
5085 swapchain->desc.multisample_type = swapchain_desc->multisample_type;
5086 swapchain->desc.multisample_quality = swapchain_desc->multisample_quality;
5094 if (FAILED(hr = wined3d_surface_update_desc(swapchain->front_buffer, swapchain->desc.backbuffer_width,
5095 swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format,
5096 swapchain->desc.multisample_type, swapchain->desc.multisample_quality)))
5099 for (i = 0; i < swapchain->desc.backbuffer_count; ++i)
5101 if (FAILED(hr = wined3d_surface_update_desc(swapchain->back_buffers[i], swapchain->desc.backbuffer_width,
5102 swapchain->desc.backbuffer_height, swapchain->desc.backbuffer_format,
5103 swapchain->desc.multisample_type, swapchain->desc.multisample_quality)))
5106 if (device->auto_depth_stencil)
5108 if (FAILED(hr = wined3d_surface_update_desc(device->auto_depth_stencil, swapchain->desc.backbuffer_width,
5109 swapchain->desc.backbuffer_height, device->auto_depth_stencil->resource.format->id,
5110 swapchain->desc.multisample_type, swapchain->desc.multisample_quality)))
5115 if (!swapchain_desc->windowed != !swapchain->desc.windowed
5116 || DisplayModeChanged)
5118 if (FAILED(hr = wined3d_set_adapter_display_mode(device->wined3d, device->adapter->ordinal, &m)))
5120 WARN("Failed to set display mode, hr %#x.\n", hr);
5121 return WINED3DERR_INVALIDCALL;
5124 if (!swapchain_desc->windowed)
5126 if (swapchain->desc.windowed)
5128 HWND focus_window = device->create_parms.focus_window;
5130 focus_window = swapchain_desc->device_window;
5131 if (FAILED(hr = wined3d_device_acquire_focus_window(device, focus_window)))
5133 ERR("Failed to acquire focus window, hr %#x.\n", hr);
5137 /* switch from windowed to fs */
5138 wined3d_device_setup_fullscreen_window(device, swapchain->device_window,
5139 swapchain_desc->backbuffer_width,
5140 swapchain_desc->backbuffer_height);
5144 /* Fullscreen -> fullscreen mode change */
5145 MoveWindow(swapchain->device_window, 0, 0,
5146 swapchain_desc->backbuffer_width,
5147 swapchain_desc->backbuffer_height,
5151 else if (!swapchain->desc.windowed)
5153 /* Fullscreen -> windowed switch */
5154 wined3d_device_restore_fullscreen_window(device, swapchain->device_window);
5155 wined3d_device_release_focus_window(device);
5157 swapchain->desc.windowed = swapchain_desc->windowed;
5159 else if (!swapchain_desc->windowed)
5161 DWORD style = device->style;
5162 DWORD exStyle = device->exStyle;
5163 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
5164 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
5165 * Reset to clear up their mess. Guild Wars also loses the device during that.
5168 device->exStyle = 0;
5169 wined3d_device_setup_fullscreen_window(device, swapchain->device_window,
5170 swapchain_desc->backbuffer_width,
5171 swapchain_desc->backbuffer_height);
5172 device->style = style;
5173 device->exStyle = exStyle;
5178 TRACE("Resetting stateblock.\n");
5179 wined3d_stateblock_decref(device->updateStateBlock);
5180 wined3d_stateblock_decref(device->stateBlock);
5182 if (device->d3d_initialized)
5183 delete_opengl_contexts(device, swapchain);
5185 /* Note: No parent needed for initial internal stateblock */
5186 hr = wined3d_stateblock_create(device, WINED3D_SBT_INIT, &device->stateBlock);
5188 ERR("Resetting the stateblock failed with error %#x.\n", hr);
5190 TRACE("Created stateblock %p.\n", device->stateBlock);
5191 device->updateStateBlock = device->stateBlock;
5192 wined3d_stateblock_incref(device->updateStateBlock);
5194 stateblock_init_default_state(device->stateBlock);
5198 struct wined3d_surface *rt = device->fb.render_targets[0];
5199 struct wined3d_state *state = &device->stateBlock->state;
5201 /* Note the min_z / max_z is not reset. */
5202 state->viewport.x = 0;
5203 state->viewport.y = 0;
5204 state->viewport.width = rt->resource.width;
5205 state->viewport.height = rt->resource.height;
5206 device_invalidate_state(device, STATE_VIEWPORT);
5208 state->scissor_rect.top = 0;
5209 state->scissor_rect.left = 0;
5210 state->scissor_rect.right = rt->resource.width;
5211 state->scissor_rect.bottom = rt->resource.height;
5212 device_invalidate_state(device, STATE_SCISSORRECT);
5215 swapchain_update_render_to_fbo(swapchain);
5216 swapchain_update_draw_bindings(swapchain);
5218 if (reset_state && device->d3d_initialized)
5219 hr = create_primary_opengl_context(device, swapchain);
5221 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
5227 HRESULT CDECL wined3d_device_set_dialog_box_mode(struct wined3d_device *device, BOOL enable_dialogs)
5229 TRACE("device %p, enable_dialogs %#x.\n", device, enable_dialogs);
5231 if (!enable_dialogs) FIXME("Dialogs cannot be disabled yet.\n");
5237 void CDECL wined3d_device_get_creation_parameters(const struct wined3d_device *device,
5238 struct wined3d_device_creation_parameters *parameters)
5240 TRACE("device %p, parameters %p.\n", device, parameters);
5242 *parameters = device->create_parms;
5245 void CDECL wined3d_device_set_gamma_ramp(const struct wined3d_device *device,
5246 UINT swapchain_idx, DWORD flags, const struct wined3d_gamma_ramp *ramp)
5248 struct wined3d_swapchain *swapchain;
5250 TRACE("device %p, swapchain_idx %u, flags %#x, ramp %p.\n",
5251 device, swapchain_idx, flags, ramp);
5253 if ((swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
5254 wined3d_swapchain_set_gamma_ramp(swapchain, flags, ramp);
5257 void CDECL wined3d_device_get_gamma_ramp(const struct wined3d_device *device,
5258 UINT swapchain_idx, struct wined3d_gamma_ramp *ramp)
5260 struct wined3d_swapchain *swapchain;
5262 TRACE("device %p, swapchain_idx %u, ramp %p.\n",
5263 device, swapchain_idx, ramp);
5265 if ((swapchain = wined3d_device_get_swapchain(device, swapchain_idx)))
5266 wined3d_swapchain_get_gamma_ramp(swapchain, ramp);
5269 void device_resource_add(struct wined3d_device *device, struct wined3d_resource *resource)
5271 TRACE("device %p, resource %p.\n", device, resource);
5273 list_add_head(&device->resources, &resource->resource_list_entry);
5276 static void device_resource_remove(struct wined3d_device *device, struct wined3d_resource *resource)
5278 TRACE("device %p, resource %p.\n", device, resource);
5280 list_remove(&resource->resource_list_entry);
5283 void device_resource_released(struct wined3d_device *device, struct wined3d_resource *resource)
5285 enum wined3d_resource_type type = resource->type;
5288 TRACE("device %p, resource %p, type %s.\n", device, resource, debug_d3dresourcetype(type));
5290 context_resource_released(device, resource, type);
5294 case WINED3D_RTYPE_SURFACE:
5296 struct wined3d_surface *surface = surface_from_resource(resource);
5298 if (!device->d3d_initialized) break;
5300 for (i = 0; i < device->adapter->gl_info.limits.buffers; ++i)
5302 if (device->fb.render_targets[i] == surface)
5304 ERR("Surface %p is still in use as render target %u.\n", surface, i);
5305 device->fb.render_targets[i] = NULL;
5309 if (device->fb.depth_stencil == surface)
5311 ERR("Surface %p is still in use as depth/stencil buffer.\n", surface);
5312 device->fb.depth_stencil = NULL;
5317 case WINED3D_RTYPE_TEXTURE:
5318 case WINED3D_RTYPE_CUBE_TEXTURE:
5319 case WINED3D_RTYPE_VOLUME_TEXTURE:
5320 for (i = 0; i < MAX_COMBINED_SAMPLERS; ++i)
5322 struct wined3d_texture *texture = wined3d_texture_from_resource(resource);
5324 if (device->stateBlock && device->stateBlock->state.textures[i] == texture)
5326 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
5327 texture, device->stateBlock, i);
5328 device->stateBlock->state.textures[i] = NULL;
5331 if (device->updateStateBlock != device->stateBlock
5332 && device->updateStateBlock->state.textures[i] == texture)
5334 ERR("Texture %p is still in use by stateblock %p, stage %u.\n",
5335 texture, device->updateStateBlock, i);
5336 device->updateStateBlock->state.textures[i] = NULL;
5341 case WINED3D_RTYPE_BUFFER:
5343 struct wined3d_buffer *buffer = buffer_from_resource(resource);
5345 for (i = 0; i < MAX_STREAMS; ++i)
5347 if (device->stateBlock && device->stateBlock->state.streams[i].buffer == buffer)
5349 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
5350 buffer, device->stateBlock, i);
5351 device->stateBlock->state.streams[i].buffer = NULL;
5354 if (device->updateStateBlock != device->stateBlock
5355 && device->updateStateBlock->state.streams[i].buffer == buffer)
5357 ERR("Buffer %p is still in use by stateblock %p, stream %u.\n",
5358 buffer, device->updateStateBlock, i);
5359 device->updateStateBlock->state.streams[i].buffer = NULL;
5364 if (device->stateBlock && device->stateBlock->state.index_buffer == buffer)
5366 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
5367 buffer, device->stateBlock);
5368 device->stateBlock->state.index_buffer = NULL;
5371 if (device->updateStateBlock != device->stateBlock
5372 && device->updateStateBlock->state.index_buffer == buffer)
5374 ERR("Buffer %p is still in use by stateblock %p as index buffer.\n",
5375 buffer, device->updateStateBlock);
5376 device->updateStateBlock->state.index_buffer = NULL;
5385 /* Remove the resource from the resourceStore */
5386 device_resource_remove(device, resource);
5388 TRACE("Resource released.\n");
5391 struct wined3d_surface * CDECL wined3d_device_get_surface_from_dc(const struct wined3d_device *device, HDC dc)
5393 struct wined3d_resource *resource;
5395 TRACE("device %p, dc %p.\n", device, dc);
5400 LIST_FOR_EACH_ENTRY(resource, &device->resources, struct wined3d_resource, resource_list_entry)
5402 if (resource->type == WINED3D_RTYPE_SURFACE)
5404 struct wined3d_surface *s = surface_from_resource(resource);
5408 TRACE("Found surface %p for dc %p.\n", s, dc);
5417 HRESULT device_init(struct wined3d_device *device, struct wined3d *wined3d,
5418 UINT adapter_idx, enum wined3d_device_type device_type, HWND focus_window, DWORD flags,
5419 BYTE surface_alignment, struct wined3d_device_parent *device_parent)
5421 struct wined3d_adapter *adapter = &wined3d->adapters[adapter_idx];
5422 const struct fragment_pipeline *fragment_pipeline;
5423 struct shader_caps shader_caps;
5424 struct fragment_caps ffp_caps;
5429 device->wined3d = wined3d;
5430 wined3d_incref(device->wined3d);
5431 device->adapter = wined3d->adapter_count ? adapter : NULL;
5432 device->device_parent = device_parent;
5433 list_init(&device->resources);
5434 list_init(&device->shaders);
5435 device->surface_alignment = surface_alignment;
5437 /* Save the creation parameters. */
5438 device->create_parms.adapter_idx = adapter_idx;
5439 device->create_parms.device_type = device_type;
5440 device->create_parms.focus_window = focus_window;
5441 device->create_parms.flags = flags;
5443 device->shader_backend = adapter->shader_backend;
5444 device->shader_backend->shader_get_caps(&adapter->gl_info, &shader_caps);
5445 device->vs_version = shader_caps.vs_version;
5446 device->gs_version = shader_caps.gs_version;
5447 device->ps_version = shader_caps.ps_version;
5448 device->d3d_vshader_constantF = shader_caps.vs_uniform_count;
5449 device->d3d_pshader_constantF = shader_caps.ps_uniform_count;
5450 device->vs_clipping = shader_caps.wined3d_caps & WINED3D_SHADER_CAP_VS_CLIPPING;
5452 fragment_pipeline = adapter->fragment_pipe;
5453 fragment_pipeline->get_caps(&adapter->gl_info, &ffp_caps);
5454 device->max_ffp_textures = ffp_caps.MaxSimultaneousTextures;
5456 if (fragment_pipeline->states
5457 && FAILED(hr = compile_state_table(device->StateTable, device->multistate_funcs,
5458 &adapter->gl_info, ffp_vertexstate_template, fragment_pipeline, misc_state_template)))
5460 ERR("Failed to compile state table, hr %#x.\n", hr);
5461 wined3d_decref(device->wined3d);
5465 device->blitter = adapter->blitter;
5467 hr = wined3d_stateblock_create(device, WINED3D_SBT_INIT, &device->stateBlock);
5470 WARN("Failed to create stateblock.\n");
5471 for (i = 0; i < sizeof(device->multistate_funcs) / sizeof(device->multistate_funcs[0]); ++i)
5473 HeapFree(GetProcessHeap(), 0, device->multistate_funcs[i]);
5475 wined3d_decref(device->wined3d);
5479 TRACE("Created stateblock %p.\n", device->stateBlock);
5480 device->updateStateBlock = device->stateBlock;
5481 wined3d_stateblock_incref(device->updateStateBlock);
5487 void device_invalidate_state(const struct wined3d_device *device, DWORD state)
5489 DWORD rep = device->StateTable[state].representative;
5490 struct wined3d_context *context;
5495 for (i = 0; i < device->context_count; ++i)
5497 context = device->contexts[i];
5498 if(isStateDirty(context, rep)) continue;
5500 context->dirtyArray[context->numDirtyEntries++] = rep;
5501 idx = rep / (sizeof(*context->isStateDirty) * CHAR_BIT);
5502 shift = rep & ((sizeof(*context->isStateDirty) * CHAR_BIT) - 1);
5503 context->isStateDirty[idx] |= (1 << shift);
5507 void get_drawable_size_fbo(const struct wined3d_context *context, UINT *width, UINT *height)
5509 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size. */
5510 *width = context->current_rt->pow2Width;
5511 *height = context->current_rt->pow2Height;
5514 void get_drawable_size_backbuffer(const struct wined3d_context *context, UINT *width, UINT *height)
5516 const struct wined3d_swapchain *swapchain = context->swapchain;
5517 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
5518 * current context's drawable, which is the size of the back buffer of the swapchain
5519 * the active context belongs to. */
5520 *width = swapchain->desc.backbuffer_width;
5521 *height = swapchain->desc.backbuffer_height;
5524 LRESULT device_process_message(struct wined3d_device *device, HWND window, BOOL unicode,
5525 UINT message, WPARAM wparam, LPARAM lparam, WNDPROC proc)
5527 if (device->filter_messages)
5529 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
5530 window, message, wparam, lparam);
5532 return DefWindowProcW(window, message, wparam, lparam);
5534 return DefWindowProcA(window, message, wparam, lparam);
5537 if (message == WM_DESTROY)
5539 TRACE("unregister window %p.\n", window);
5540 wined3d_unregister_window(window);
5542 if (InterlockedCompareExchangePointer((void **)&device->focus_window, NULL, window) != window)
5543 ERR("Window %p is not the focus window for device %p.\n", window, device);
5545 else if (message == WM_DISPLAYCHANGE)
5547 device->device_parent->ops->mode_changed(device->device_parent);
5551 return CallWindowProcW(proc, window, message, wparam, lparam);
5553 return CallWindowProcA(proc, window, message, wparam, lparam);