wined3d: Move struct wined3d_rendertarget_view_vk to wined3d_vk.h.
[wine.git] / dlls / wined3d / context.c
blobf9af58936a6a9540afee35df96e8eee869ba7f99
1 /*
2 * Context and render target management in wined3d
4 * Copyright 2002-2004 Jason Edmeades
5 * Copyright 2002-2004 Raphael Junqueira
6 * Copyright 2004 Christian Costa
7 * Copyright 2005 Oliver Stieber
8 * Copyright 2006, 2008 Henri Verbeet
9 * Copyright 2007-2011, 2013 Stefan Dösinger for CodeWeavers
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
27 #include "wined3d_private.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
30 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
32 void context_resource_released(const struct wined3d_device *device, struct wined3d_resource *resource)
34 unsigned int i;
36 for (i = 0; i < device->context_count; ++i)
38 struct wined3d_context *context = device->contexts[i];
40 if (&context->current_rt.texture->resource == resource)
42 context->current_rt.texture = NULL;
43 context->current_rt.sub_resource_idx = 0;
48 void wined3d_context_cleanup(struct wined3d_context *context)
52 /* This is used when a context for render target A is active, but a separate context is
53 * needed to access the WGL framebuffer for render target B. Re-acquire a context for rt
54 * A to avoid breaking caller code. */
55 void context_restore(struct wined3d_context *context, struct wined3d_texture *texture, unsigned int sub_resource_idx)
57 if (context->current_rt.texture != texture || context->current_rt.sub_resource_idx != sub_resource_idx)
59 context_release(context);
60 context = context_acquire(texture->resource.device, texture, sub_resource_idx);
63 context_release(context);
66 void context_invalidate_compute_state(struct wined3d_context *context, DWORD state_id)
68 DWORD representative = context->state_table[state_id].representative - STATE_COMPUTE_OFFSET;
69 unsigned int index, shift;
71 index = representative / (sizeof(*context->dirty_compute_states) * CHAR_BIT);
72 shift = representative & (sizeof(*context->dirty_compute_states) * CHAR_BIT - 1);
73 context->dirty_compute_states[index] |= (1u << shift);
76 void context_invalidate_state(struct wined3d_context *context, unsigned int state_id)
78 unsigned int representative = context->state_table[state_id].representative;
79 unsigned int index, shift;
81 if (!representative)
82 ERR("Invalidating representative 0, state_id %u.\n", state_id);
84 index = representative / (sizeof(*context->dirty_graphics_states) * CHAR_BIT);
85 shift = representative & ((sizeof(*context->dirty_graphics_states) * CHAR_BIT) - 1);
86 context->dirty_graphics_states[index] |= (1u << shift);
89 void wined3d_context_init(struct wined3d_context *context, struct wined3d_swapchain *swapchain)
91 struct wined3d_device *device = swapchain->device;
92 DWORD state;
94 context->d3d_info = &device->adapter->d3d_info;
95 context->state_table = device->state_table;
97 /* Mark all states dirty to force a proper initialization of the states on
98 * the first use of the context. Compute states do not need initialization. */
99 for (state = 0; state <= STATE_HIGHEST; ++state)
101 if (context->state_table[state].representative && !STATE_IS_COMPUTE(state))
102 context_invalidate_state(context, state);
105 context->device = device;
106 context->swapchain = swapchain;
107 context->current_rt.texture = swapchain->front_buffer;
108 context->current_rt.sub_resource_idx = 0;
110 context->shader_update_mask = (1u << WINED3D_SHADER_TYPE_PIXEL)
111 | (1u << WINED3D_SHADER_TYPE_VERTEX)
112 | (1u << WINED3D_SHADER_TYPE_GEOMETRY)
113 | (1u << WINED3D_SHADER_TYPE_HULL)
114 | (1u << WINED3D_SHADER_TYPE_DOMAIN)
115 | (1u << WINED3D_SHADER_TYPE_COMPUTE);
118 HRESULT wined3d_context_no3d_init(struct wined3d_context *context_no3d, struct wined3d_swapchain *swapchain)
120 TRACE("context_no3d %p, swapchain %p.\n", context_no3d, swapchain);
122 wined3d_context_init(context_no3d, swapchain);
124 return WINED3D_OK;
127 static BOOL fixed_get_input(BYTE usage, BYTE usage_idx, unsigned int *regnum)
129 if ((usage == WINED3D_DECL_USAGE_POSITION || usage == WINED3D_DECL_USAGE_POSITIONT) && !usage_idx)
130 *regnum = WINED3D_FFP_POSITION;
131 else if (usage == WINED3D_DECL_USAGE_BLEND_WEIGHT && !usage_idx)
132 *regnum = WINED3D_FFP_BLENDWEIGHT;
133 else if (usage == WINED3D_DECL_USAGE_BLEND_INDICES && !usage_idx)
134 *regnum = WINED3D_FFP_BLENDINDICES;
135 else if (usage == WINED3D_DECL_USAGE_NORMAL && !usage_idx)
136 *regnum = WINED3D_FFP_NORMAL;
137 else if (usage == WINED3D_DECL_USAGE_PSIZE && !usage_idx)
138 *regnum = WINED3D_FFP_PSIZE;
139 else if (usage == WINED3D_DECL_USAGE_COLOR && !usage_idx)
140 *regnum = WINED3D_FFP_DIFFUSE;
141 else if (usage == WINED3D_DECL_USAGE_COLOR && usage_idx == 1)
142 *regnum = WINED3D_FFP_SPECULAR;
143 else if (usage == WINED3D_DECL_USAGE_TEXCOORD && usage_idx < WINED3DDP_MAXTEXCOORD)
144 *regnum = WINED3D_FFP_TEXCOORD0 + usage_idx;
145 else
147 WARN("Unsupported input stream [usage=%s, usage_idx=%u].\n", debug_d3ddeclusage(usage), usage_idx);
148 *regnum = ~0u;
149 return FALSE;
152 return TRUE;
155 /* Context activation is done by the caller. */
156 void wined3d_stream_info_from_declaration(struct wined3d_stream_info *stream_info,
157 const struct wined3d_state *state, const struct wined3d_d3d_info *d3d_info)
159 /* We need to deal with frequency data! */
160 struct wined3d_vertex_declaration *declaration = state->vertex_declaration;
161 BOOL generic_attributes = d3d_info->ffp_generic_attributes;
162 BOOL use_vshader = use_vs(state);
163 unsigned int i;
165 stream_info->use_map = 0;
166 stream_info->swizzle_map = 0;
167 stream_info->position_transformed = 0;
169 if (!declaration)
170 return;
172 stream_info->position_transformed = declaration->position_transformed;
174 /* Translate the declaration into strided data. */
175 for (i = 0; i < declaration->element_count; ++i)
177 const struct wined3d_vertex_declaration_element *element = &declaration->elements[i];
178 const struct wined3d_stream_state *stream = &state->streams[element->input_slot];
179 BOOL stride_used;
180 unsigned int idx;
182 TRACE("%p Element %p (%u of %u).\n", declaration->elements,
183 element, i + 1, declaration->element_count);
185 if (!stream->buffer)
186 continue;
188 TRACE("offset %u input_slot %u usage_idx %d.\n", element->offset, element->input_slot, element->usage_idx);
190 if (use_vshader)
192 if (element->output_slot == WINED3D_OUTPUT_SLOT_UNUSED)
194 stride_used = FALSE;
196 else if (element->output_slot == WINED3D_OUTPUT_SLOT_SEMANTIC)
198 /* TODO: Assuming vertexdeclarations are usually used with the
199 * same or a similar shader, it might be worth it to store the
200 * last used output slot and try that one first. */
201 stride_used = vshader_get_input(state->shader[WINED3D_SHADER_TYPE_VERTEX],
202 element->usage, element->usage_idx, &idx);
204 else
206 idx = element->output_slot;
207 stride_used = TRUE;
210 else
212 if (!generic_attributes && !element->ffp_valid)
214 WARN("Skipping unsupported fixed function element of format %s and usage %s.\n",
215 debug_d3dformat(element->format->id), debug_d3ddeclusage(element->usage));
216 stride_used = FALSE;
218 else
220 stride_used = fixed_get_input(element->usage, element->usage_idx, &idx);
224 if (stride_used)
226 TRACE("Load %s array %u [usage %s, usage_idx %u, "
227 "input_slot %u, offset %u, stride %u, format %s, class %s, step_rate %u].\n",
228 use_vshader ? "shader": "fixed function", idx,
229 debug_d3ddeclusage(element->usage), element->usage_idx, element->input_slot,
230 element->offset, stream->stride, debug_d3dformat(element->format->id),
231 debug_d3dinput_classification(element->input_slot_class), element->instance_data_step_rate);
233 stream_info->elements[idx].format = element->format;
234 stream_info->elements[idx].data.buffer_object = 0;
235 stream_info->elements[idx].data.addr = (BYTE *)NULL + stream->offset + element->offset;
236 stream_info->elements[idx].stride = stream->stride;
237 stream_info->elements[idx].stream_idx = element->input_slot;
238 if (stream->flags & WINED3DSTREAMSOURCE_INSTANCEDATA)
240 stream_info->elements[idx].divisor = 1;
241 stream_info->elements[idx].instanced = true;
243 else if (element->input_slot_class == WINED3D_INPUT_PER_INSTANCE_DATA)
245 stream_info->elements[idx].divisor = element->instance_data_step_rate;
246 stream_info->elements[idx].instanced = true;
248 else
250 stream_info->elements[idx].divisor = 0;
251 stream_info->elements[idx].instanced = false;
254 if (!d3d_info->vertex_bgra && element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
256 stream_info->swizzle_map |= 1u << idx;
258 stream_info->use_map |= 1u << idx;
263 /* Context activation is done by the caller. */
264 void context_update_stream_info(struct wined3d_context *context, const struct wined3d_state *state)
266 struct wined3d_stream_info *stream_info = &context->stream_info;
267 const struct wined3d_d3d_info *d3d_info = context->d3d_info;
268 DWORD prev_all_vbo = stream_info->all_vbo;
269 unsigned int i;
270 uint32_t map;
272 wined3d_stream_info_from_declaration(stream_info, state, d3d_info);
274 stream_info->all_vbo = 1;
275 map = stream_info->use_map;
276 while (map)
278 struct wined3d_stream_info_element *element;
279 struct wined3d_bo_address data;
280 struct wined3d_buffer *buffer;
282 i = wined3d_bit_scan(&map);
283 element = &stream_info->elements[i];
284 buffer = state->streams[element->stream_idx].buffer;
286 /* We can't use VBOs if the base vertex index is negative. OpenGL
287 * doesn't accept negative offsets (or rather offsets bigger than the
288 * VBO, because the pointer is unsigned), so use system memory
289 * sources. In most sane cases the pointer - offset will still be > 0,
290 * otherwise it will wrap around to some big value. Hope that with the
291 * indices the driver wraps it back internally. If not,
292 * draw_primitive_immediate_mode() is needed, including a vertex buffer
293 * path. */
294 if (state->load_base_vertex_index < 0)
296 WARN_(d3d_perf)("load_base_vertex_index is < 0 (%d), not using VBOs.\n",
297 state->load_base_vertex_index);
298 element->data.buffer_object = 0;
299 element->data.addr += (ULONG_PTR)wined3d_buffer_load_sysmem(buffer, context);
300 if ((UINT_PTR)element->data.addr < -state->load_base_vertex_index * element->stride)
301 FIXME("System memory vertex data load offset is negative!\n");
303 else
305 wined3d_buffer_load(buffer, context, state);
306 wined3d_buffer_get_memory(buffer, context, &data);
307 element->data.buffer_object = data.buffer_object;
308 element->data.addr += (ULONG_PTR)data.addr;
311 if (!element->data.buffer_object)
312 stream_info->all_vbo = 0;
314 TRACE("Load array %u %s.\n", i, debug_bo_address(&element->data));
317 if (prev_all_vbo != stream_info->all_vbo)
318 context_invalidate_state(context, STATE_INDEXBUFFER);
320 context->use_immediate_mode_draw = FALSE;
322 if (stream_info->all_vbo)
323 return;
325 if (!use_vs(state))
327 WORD slow_mask = -!d3d_info->ffp_generic_attributes & (1u << WINED3D_FFP_PSIZE);
328 slow_mask |= -(!d3d_info->vertex_bgra && !d3d_info->ffp_generic_attributes)
329 & ((1u << WINED3D_FFP_DIFFUSE) | (1u << WINED3D_FFP_SPECULAR) | (1u << WINED3D_FFP_BLENDWEIGHT));
331 if ((stream_info->position_transformed && !d3d_info->xyzrhw)
332 || (stream_info->use_map & slow_mask))
333 context->use_immediate_mode_draw = TRUE;
337 static bool is_resource_rtv_bound(const struct wined3d_state *state,
338 const struct wined3d_resource *resource)
340 unsigned int i;
342 if (!resource->rtv_bind_count_device)
343 return false;
345 for (i = 0; i < ARRAY_SIZE(state->fb.render_targets); ++i)
347 if (state->fb.render_targets[i] && state->fb.render_targets[i]->resource == resource)
348 return true;
351 return false;
354 /* Context activation is done by the caller. */
355 static void context_preload_texture(struct wined3d_context *context,
356 const struct wined3d_state *state, unsigned int idx)
358 struct wined3d_texture *texture;
360 if (!(texture = state->textures[idx]))
361 return;
363 if (is_resource_rtv_bound(state, &texture->resource)
364 || (state->fb.depth_stencil && state->fb.depth_stencil->resource == &texture->resource))
365 context->uses_fbo_attached_resources = 1;
367 wined3d_texture_load(texture, context, is_srgb_enabled(state->sampler_states[idx]));
370 /* Context activation is done by the caller. */
371 void context_preload_textures(struct wined3d_context *context, const struct wined3d_state *state)
373 unsigned int i;
375 if (use_vs(state))
377 for (i = 0; i < WINED3D_MAX_VERTEX_SAMPLERS; ++i)
379 if (state->shader[WINED3D_SHADER_TYPE_VERTEX]->reg_maps.resource_info[i].type)
380 context_preload_texture(context, state, WINED3D_MAX_FRAGMENT_SAMPLERS + i);
384 if (use_ps(state))
386 for (i = 0; i < WINED3D_MAX_FRAGMENT_SAMPLERS; ++i)
388 if (state->shader[WINED3D_SHADER_TYPE_PIXEL]->reg_maps.resource_info[i].type)
389 context_preload_texture(context, state, i);
392 else
394 uint32_t ffu_map = context->fixed_function_usage_map;
396 while (ffu_map)
398 i = wined3d_bit_scan(&ffu_map);
399 context_preload_texture(context, state, i);