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
)
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 index
= representative
/ (sizeof(*context
->dirty_graphics_states
) * CHAR_BIT
);
82 shift
= representative
& ((sizeof(*context
->dirty_graphics_states
) * CHAR_BIT
) - 1);
83 context
->dirty_graphics_states
[index
] |= (1u << shift
);
86 void wined3d_context_init(struct wined3d_context
*context
, struct wined3d_swapchain
*swapchain
)
88 struct wined3d_device
*device
= swapchain
->device
;
91 context
->d3d_info
= &device
->adapter
->d3d_info
;
92 context
->state_table
= device
->state_table
;
94 /* Mark all states dirty to force a proper initialization of the states on
95 * the first use of the context. Compute states do not need initialization. */
96 for (state
= 0; state
<= STATE_HIGHEST
; ++state
)
98 if (context
->state_table
[state
].representative
&& !STATE_IS_COMPUTE(state
))
99 context_invalidate_state(context
, state
);
102 context
->device
= device
;
103 context
->swapchain
= swapchain
;
104 context
->current_rt
.texture
= swapchain
->front_buffer
;
105 context
->current_rt
.sub_resource_idx
= 0;
107 context
->shader_update_mask
= (1u << WINED3D_SHADER_TYPE_PIXEL
)
108 | (1u << WINED3D_SHADER_TYPE_VERTEX
)
109 | (1u << WINED3D_SHADER_TYPE_GEOMETRY
)
110 | (1u << WINED3D_SHADER_TYPE_HULL
)
111 | (1u << WINED3D_SHADER_TYPE_DOMAIN
)
112 | (1u << WINED3D_SHADER_TYPE_COMPUTE
);
115 HRESULT
wined3d_context_no3d_init(struct wined3d_context
*context_no3d
, struct wined3d_swapchain
*swapchain
)
117 TRACE("context_no3d %p, swapchain %p.\n", context_no3d
, swapchain
);
119 wined3d_context_init(context_no3d
, swapchain
);
124 static BOOL
fixed_get_input(BYTE usage
, BYTE usage_idx
, unsigned int *regnum
)
126 if ((usage
== WINED3D_DECL_USAGE_POSITION
|| usage
== WINED3D_DECL_USAGE_POSITIONT
) && !usage_idx
)
127 *regnum
= WINED3D_FFP_POSITION
;
128 else if (usage
== WINED3D_DECL_USAGE_BLEND_WEIGHT
&& !usage_idx
)
129 *regnum
= WINED3D_FFP_BLENDWEIGHT
;
130 else if (usage
== WINED3D_DECL_USAGE_BLEND_INDICES
&& !usage_idx
)
131 *regnum
= WINED3D_FFP_BLENDINDICES
;
132 else if (usage
== WINED3D_DECL_USAGE_NORMAL
&& !usage_idx
)
133 *regnum
= WINED3D_FFP_NORMAL
;
134 else if (usage
== WINED3D_DECL_USAGE_PSIZE
&& !usage_idx
)
135 *regnum
= WINED3D_FFP_PSIZE
;
136 else if (usage
== WINED3D_DECL_USAGE_COLOR
&& !usage_idx
)
137 *regnum
= WINED3D_FFP_DIFFUSE
;
138 else if (usage
== WINED3D_DECL_USAGE_COLOR
&& usage_idx
== 1)
139 *regnum
= WINED3D_FFP_SPECULAR
;
140 else if (usage
== WINED3D_DECL_USAGE_TEXCOORD
&& usage_idx
< WINED3DDP_MAXTEXCOORD
)
141 *regnum
= WINED3D_FFP_TEXCOORD0
+ usage_idx
;
144 WARN("Unsupported input stream [usage=%s, usage_idx=%u].\n", debug_d3ddeclusage(usage
), usage_idx
);
152 /* Context activation is done by the caller. */
153 void wined3d_stream_info_from_declaration(struct wined3d_stream_info
*stream_info
,
154 const struct wined3d_state
*state
, const struct wined3d_d3d_info
*d3d_info
)
156 /* We need to deal with frequency data! */
157 struct wined3d_vertex_declaration
*declaration
= state
->vertex_declaration
;
158 BOOL generic_attributes
= d3d_info
->ffp_generic_attributes
;
159 BOOL use_vshader
= use_vs(state
);
162 stream_info
->use_map
= 0;
163 stream_info
->swizzle_map
= 0;
164 stream_info
->position_transformed
= 0;
169 stream_info
->position_transformed
= declaration
->position_transformed
;
171 /* Translate the declaration into strided data. */
172 for (i
= 0; i
< declaration
->element_count
; ++i
)
174 const struct wined3d_vertex_declaration_element
*element
= &declaration
->elements
[i
];
175 const struct wined3d_stream_state
*stream
= &state
->streams
[element
->input_slot
];
179 TRACE("%p Element %p (%u of %u).\n", declaration
->elements
,
180 element
, i
+ 1, declaration
->element_count
);
185 TRACE("offset %u input_slot %u usage_idx %d.\n", element
->offset
, element
->input_slot
, element
->usage_idx
);
189 if (element
->output_slot
== WINED3D_OUTPUT_SLOT_UNUSED
)
193 else if (element
->output_slot
== WINED3D_OUTPUT_SLOT_SEMANTIC
)
195 /* TODO: Assuming vertexdeclarations are usually used with the
196 * same or a similar shader, it might be worth it to store the
197 * last used output slot and try that one first. */
198 stride_used
= vshader_get_input(state
->shader
[WINED3D_SHADER_TYPE_VERTEX
],
199 element
->usage
, element
->usage_idx
, &idx
);
203 idx
= element
->output_slot
;
209 if (!generic_attributes
&& !element
->ffp_valid
)
211 WARN("Skipping unsupported fixed function element of format %s and usage %s.\n",
212 debug_d3dformat(element
->format
->id
), debug_d3ddeclusage(element
->usage
));
217 stride_used
= fixed_get_input(element
->usage
, element
->usage_idx
, &idx
);
223 TRACE("Load %s array %u [usage %s, usage_idx %u, "
224 "input_slot %u, offset %u, stride %u, format %s, class %s, step_rate %u].\n",
225 use_vshader
? "shader": "fixed function", idx
,
226 debug_d3ddeclusage(element
->usage
), element
->usage_idx
, element
->input_slot
,
227 element
->offset
, stream
->stride
, debug_d3dformat(element
->format
->id
),
228 debug_d3dinput_classification(element
->input_slot_class
), element
->instance_data_step_rate
);
230 stream_info
->elements
[idx
].format
= element
->format
;
231 stream_info
->elements
[idx
].data
.buffer_object
= 0;
232 stream_info
->elements
[idx
].data
.addr
= (BYTE
*)NULL
+ stream
->offset
+ element
->offset
;
233 stream_info
->elements
[idx
].stride
= stream
->stride
;
234 stream_info
->elements
[idx
].stream_idx
= element
->input_slot
;
235 if (stream
->flags
& WINED3DSTREAMSOURCE_INSTANCEDATA
)
237 stream_info
->elements
[idx
].divisor
= 1;
238 stream_info
->elements
[idx
].instanced
= true;
240 else if (element
->input_slot_class
== WINED3D_INPUT_PER_INSTANCE_DATA
)
242 stream_info
->elements
[idx
].divisor
= element
->instance_data_step_rate
;
243 stream_info
->elements
[idx
].instanced
= true;
247 stream_info
->elements
[idx
].divisor
= 0;
248 stream_info
->elements
[idx
].instanced
= false;
251 if (!d3d_info
->vertex_bgra
&& element
->format
->id
== WINED3DFMT_B8G8R8A8_UNORM
)
253 stream_info
->swizzle_map
|= 1u << idx
;
255 stream_info
->use_map
|= 1u << idx
;
260 /* Context activation is done by the caller. */
261 void context_update_stream_info(struct wined3d_context
*context
, const struct wined3d_state
*state
)
263 struct wined3d_stream_info
*stream_info
= &context
->stream_info
;
264 const struct wined3d_d3d_info
*d3d_info
= context
->d3d_info
;
265 DWORD prev_all_vbo
= stream_info
->all_vbo
;
269 wined3d_stream_info_from_declaration(stream_info
, state
, d3d_info
);
271 stream_info
->all_vbo
= 1;
272 map
= stream_info
->use_map
;
275 struct wined3d_stream_info_element
*element
;
276 struct wined3d_bo_address data
;
277 struct wined3d_buffer
*buffer
;
279 i
= wined3d_bit_scan(&map
);
280 element
= &stream_info
->elements
[i
];
281 buffer
= state
->streams
[element
->stream_idx
].buffer
;
283 /* We can't use VBOs if the base vertex index is negative. OpenGL
284 * doesn't accept negative offsets (or rather offsets bigger than the
285 * VBO, because the pointer is unsigned), so use system memory
286 * sources. In most sane cases the pointer - offset will still be > 0,
287 * otherwise it will wrap around to some big value. Hope that with the
288 * indices the driver wraps it back internally. If not,
289 * draw_primitive_immediate_mode() is needed, including a vertex buffer
291 if (state
->load_base_vertex_index
< 0)
293 WARN_(d3d_perf
)("load_base_vertex_index is < 0 (%d), not using VBOs.\n",
294 state
->load_base_vertex_index
);
295 element
->data
.buffer_object
= 0;
296 element
->data
.addr
+= (ULONG_PTR
)wined3d_buffer_load_sysmem(buffer
, context
);
297 if ((UINT_PTR
)element
->data
.addr
< -state
->load_base_vertex_index
* element
->stride
)
298 FIXME("System memory vertex data load offset is negative!\n");
302 wined3d_buffer_load(buffer
, context
, state
);
303 wined3d_buffer_get_memory(buffer
, context
, &data
);
304 element
->data
.buffer_object
= data
.buffer_object
;
305 element
->data
.addr
+= (ULONG_PTR
)data
.addr
;
308 if (!element
->data
.buffer_object
)
309 stream_info
->all_vbo
= 0;
311 TRACE("Load array %u %s.\n", i
, debug_bo_address(&element
->data
));
314 if (prev_all_vbo
!= stream_info
->all_vbo
)
315 context_invalidate_state(context
, STATE_INDEXBUFFER
);
317 context
->use_immediate_mode_draw
= FALSE
;
319 if (stream_info
->all_vbo
)
324 WORD slow_mask
= -!d3d_info
->ffp_generic_attributes
& (1u << WINED3D_FFP_PSIZE
);
325 slow_mask
|= -(!d3d_info
->vertex_bgra
&& !d3d_info
->ffp_generic_attributes
)
326 & ((1u << WINED3D_FFP_DIFFUSE
) | (1u << WINED3D_FFP_SPECULAR
) | (1u << WINED3D_FFP_BLENDWEIGHT
));
328 if ((stream_info
->position_transformed
&& !d3d_info
->xyzrhw
)
329 || (stream_info
->use_map
& slow_mask
))
330 context
->use_immediate_mode_draw
= TRUE
;
334 static bool is_resource_rtv_bound(const struct wined3d_state
*state
,
335 const struct wined3d_resource
*resource
)
339 if (!resource
->rtv_bind_count_device
)
342 for (i
= 0; i
< ARRAY_SIZE(state
->fb
.render_targets
); ++i
)
344 if (state
->fb
.render_targets
[i
] && state
->fb
.render_targets
[i
]->resource
== resource
)
351 /* Context activation is done by the caller. */
352 static void context_preload_texture(struct wined3d_context
*context
,
353 const struct wined3d_state
*state
, unsigned int idx
)
355 struct wined3d_texture
*texture
;
357 if (!(texture
= state
->textures
[idx
]))
360 if (is_resource_rtv_bound(state
, &texture
->resource
)
361 || (state
->fb
.depth_stencil
&& state
->fb
.depth_stencil
->resource
== &texture
->resource
))
362 context
->uses_fbo_attached_resources
= 1;
364 wined3d_texture_load(texture
, context
, is_srgb_enabled(state
->sampler_states
[idx
]));
367 /* Context activation is done by the caller. */
368 void context_preload_textures(struct wined3d_context
*context
, const struct wined3d_state
*state
)
374 for (i
= 0; i
< WINED3D_MAX_VERTEX_SAMPLERS
; ++i
)
376 if (state
->shader
[WINED3D_SHADER_TYPE_VERTEX
]->reg_maps
.resource_info
[i
].type
)
377 context_preload_texture(context
, state
, WINED3D_MAX_FRAGMENT_SAMPLERS
+ i
);
383 for (i
= 0; i
< WINED3D_MAX_FRAGMENT_SAMPLERS
; ++i
)
385 if (state
->shader
[WINED3D_SHADER_TYPE_PIXEL
]->reg_maps
.resource_info
[i
].type
)
386 context_preload_texture(context
, state
, i
);
391 uint32_t ffu_map
= context
->fixed_function_usage_map
;
395 i
= wined3d_bit_scan(&ffu_map
);
396 context_preload_texture(context
, state
, i
);