vkd3d: Implement support for rendering to NULL/unbound RTV.

Need to use fallback pipeline system here.
Keep track of active masks for PSO and current render target.
The intersection of those sets are the attachments which should be
active in the render pass.

Signed-off-by: Hans-Kristian Arntzen <post@arntzen-software.no>
This commit is contained in:
Hans-Kristian Arntzen 2021-09-28 14:24:12 +02:00
parent b0f3512b8b
commit af822939fb
3 changed files with 56 additions and 27 deletions

View File

@ -4215,6 +4215,7 @@ static void d3d12_command_list_reset_api_state(struct d3d12_command_list *list,
list->fb_width = 0;
list->fb_height = 0;
list->fb_layer_count = 0;
list->rtv_nonnull_mask = 0;
list->xfb_enabled = false;
@ -4398,6 +4399,7 @@ static bool d3d12_command_list_update_current_framebuffer(struct d3d12_command_l
struct d3d12_graphics_pipeline_state *graphics;
VkFramebuffer vk_framebuffer;
unsigned int view_count;
uint32_t rtv_mask;
VkExtent3D extent;
unsigned int i;
@ -4405,22 +4407,14 @@ static bool d3d12_command_list_update_current_framebuffer(struct d3d12_command_l
return true;
graphics = &list->state->graphics;
rtv_mask = graphics->rtv_active_mask & list->rtv_nonnull_mask;
view_count = 0;
for (i = 0, view_count = 0; i < graphics->rt_count; ++i)
/* The pipeline has fallback render passes / PSO in case we're
* attempting to render to unbound RTV. */
while (rtv_mask)
{
if (graphics->null_attachment_mask & (1u << i))
{
if (list->rtvs[i].view)
WARN("Expected NULL RTV for attachment %u.\n", i);
continue;
}
if (!list->rtvs[i].view)
{
FIXME_ONCE("Invalid RTV for attachment %u.\n", i);
return false;
}
i = vkd3d_bitmask_iter32(&rtv_mask);
views[view_count++] = list->rtvs[i].view->vk_image_view;
}
@ -4574,11 +4568,12 @@ static bool d3d12_command_list_update_graphics_pipeline(struct d3d12_command_lis
/* Try to grab the pipeline we compiled ahead of time. If we cannot do so, fall back. */
if (!(vk_pipeline = d3d12_pipeline_state_get_pipeline(list->state,
&list->dynamic_state, list->dsv.format, &render_pass_compat, &new_active_flags,
&list->dynamic_state, list->rtv_nonnull_mask, list->dsv.format,
&render_pass_compat, &new_active_flags,
variant_flags)))
{
if (!(vk_pipeline = d3d12_pipeline_state_get_or_create_pipeline(list->state,
&list->dynamic_state, list->dsv.format,
&list->dynamic_state, list->rtv_nonnull_mask, list->dsv.format,
&render_pass_compat, &new_active_flags, variant_flags)))
return false;
}
@ -7690,6 +7685,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(d3d12_comman
/* Need to deduce DSV layouts again. */
list->dsv_layout = VK_IMAGE_LAYOUT_UNDEFINED;
list->dsv_plane_optimal_mask = 0;
list->rtv_nonnull_mask = 0;
for (i = 0; i < render_target_descriptor_count; ++i)
{
@ -7712,6 +7708,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(d3d12_comman
d3d12_command_list_track_resource_usage(list, rtv_desc->resource, true);
list->rtvs[i] = *rtv_desc;
list->rtv_nonnull_mask |= 1u << i;
list->fb_width = min(list->fb_width, rtv_desc->width);
list->fb_height = min(list->fb_height, rtv_desc->height);
list->fb_layer_count = min(list->fb_layer_count, rtv_desc->layer_count);

View File

@ -1346,7 +1346,8 @@ struct vkd3d_render_pass_entry
VkRenderPass vk_render_pass;
};
STATIC_ASSERT(sizeof(struct vkd3d_render_pass_key) == 48);
/* Ensure that key is packed, and can be memcmp'd. */
STATIC_ASSERT(sizeof(struct vkd3d_render_pass_key) == 52);
static VkImageLayout vkd3d_render_pass_get_depth_stencil_layout(const struct vkd3d_render_pass_key *key)
{
@ -1399,7 +1400,7 @@ static HRESULT vkd3d_render_pass_cache_create_pass_locked(struct vkd3d_render_pa
for (index = 0, attachment_index = 0; index < rt_count; ++index)
{
if (!key->vk_formats[index])
if (!(key->rtv_active_mask & (1u << index)))
{
attachment_references[index].sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
attachment_references[index].pNext = NULL;
@ -2657,7 +2658,7 @@ STATIC_ASSERT(sizeof(struct vkd3d_shader_transform_feedback_element) == sizeof(D
static HRESULT d3d12_graphics_pipeline_state_create_render_pass_for_plane_mask(
struct d3d12_graphics_pipeline_state *graphics, struct d3d12_device *device,
const struct vkd3d_format *dynamic_dsv_format,
uint32_t rtv_active_mask, const struct vkd3d_format *dynamic_dsv_format,
uint32_t plane_optimal_mask,
VkRenderPass *vk_render_pass,
uint32_t *out_plane_optimal_mask,
@ -2670,6 +2671,7 @@ static HRESULT d3d12_graphics_pipeline_state_create_render_pass_for_plane_mask(
memcpy(key.vk_formats, graphics->rtv_formats, sizeof(graphics->rtv_formats));
key.attachment_count = graphics->rt_count;
key.rtv_active_mask = rtv_active_mask;
key.flags = 0;
if (graphics->dsv_format)
@ -2767,7 +2769,7 @@ static HRESULT d3d12_graphics_pipeline_state_create_render_pass_for_plane_mask(
static HRESULT d3d12_graphics_pipeline_state_create_render_pass(
struct d3d12_graphics_pipeline_state *graphics, struct d3d12_device *device,
const struct vkd3d_format *dynamic_dsv_format,
uint32_t rtv_active_mask, const struct vkd3d_format *dynamic_dsv_format,
struct vkd3d_render_pass_compatibility *render_pass_compat,
uint32_t *out_plane_optimal_mask,
uint32_t variant_flags)
@ -2779,7 +2781,7 @@ static HRESULT d3d12_graphics_pipeline_state_create_render_pass(
plane_optimal_mask++)
{
if (FAILED(hr = d3d12_graphics_pipeline_state_create_render_pass_for_plane_mask(
graphics, device, dynamic_dsv_format,
graphics, device, rtv_active_mask, dynamic_dsv_format,
plane_optimal_mask, &render_pass_compat->dsv_layouts[plane_optimal_mask],
plane_optimal_mask == 0 ? out_plane_optimal_mask : NULL, variant_flags)))
{
@ -3025,6 +3027,7 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s
}
graphics->null_attachment_mask = 0;
graphics->rtv_active_mask = 0;
for (i = 0; i < rt_count; ++i)
{
const D3D12_RENDER_TARGET_BLEND_DESC *rt_desc;
@ -3039,6 +3042,7 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s
{
ps_output_swizzle[i] = vkd3d_get_rt_format_swizzle(format);
graphics->rtv_formats[i] = format->vk_format;
graphics->rtv_active_mask |= 1u << i;
}
else
{
@ -3543,7 +3547,8 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s
continue;
if (FAILED(hr = d3d12_graphics_pipeline_state_create_render_pass(graphics,
device, NULL, &graphics->render_pass[i], &graphics->dsv_plane_optimal_mask, i)))
device, graphics->rtv_active_mask, NULL,
&graphics->render_pass[i], &graphics->dsv_plane_optimal_mask, i)))
goto fail;
}
}
@ -3829,6 +3834,7 @@ VkPipeline d3d12_pipeline_state_create_pipeline_variant(struct d3d12_pipeline_st
struct d3d12_device *device = state->device;
VkGraphicsPipelineCreateInfo pipeline_desc;
VkPipelineViewportStateCreateInfo vp_desc;
uint32_t rtv_active_mask;
VkPipeline vk_pipeline;
unsigned int i;
VkResult vr;
@ -3915,7 +3921,15 @@ VkPipeline d3d12_pipeline_state_create_pipeline_variant(struct d3d12_pipeline_st
dsv_format ? dsv_format->vk_format : VK_FORMAT_UNDEFINED);
}
if (FAILED(hr = d3d12_graphics_pipeline_state_create_render_pass(graphics, device, dsv_format,
rtv_active_mask = key ? key->rtv_active_mask : graphics->rtv_active_mask;
if (graphics->rtv_active_mask != rtv_active_mask)
{
TRACE("Compiling %p with fallback RTV write mask (PSO = 0x%x, RT = 0x%x).\n", state,
state->graphics.rtv_active_mask, key->rtv_active_mask);
}
if (FAILED(hr = d3d12_graphics_pipeline_state_create_render_pass(graphics, device,
rtv_active_mask, dsv_format,
render_pass_compat, &graphics->dsv_plane_optimal_mask, variant_flags)))
return VK_NULL_HANDLE;
@ -3970,7 +3984,8 @@ static bool d3d12_pipeline_state_can_use_dynamic_stride(struct d3d12_pipeline_st
}
VkPipeline d3d12_pipeline_state_get_pipeline(struct d3d12_pipeline_state *state,
const struct vkd3d_dynamic_state *dyn_state, const struct vkd3d_format *dsv_format,
const struct vkd3d_dynamic_state *dyn_state,
uint32_t rtv_nonnull_mask, const struct vkd3d_format *dsv_format,
const struct vkd3d_render_pass_compatibility **render_pass_compat,
uint32_t *dynamic_state_flags, uint32_t variant_flags)
{
@ -3991,6 +4006,15 @@ VkPipeline d3d12_pipeline_state_get_pipeline(struct d3d12_pipeline_state *state,
return VK_NULL_HANDLE;
}
/* Case where we render to null or unbound RTV.
* We'll need to nop out the attachments in the render pass / PSO. */
if (state->graphics.rtv_active_mask & ~rtv_nonnull_mask)
{
TRACE("RTV mismatch. Writing to attachment mask 0x%x, but only 0x%x RTVs are bound.\n",
state->graphics.rtv_active_mask, rtv_nonnull_mask);
return VK_NULL_HANDLE;
}
if (!d3d12_pipeline_state_can_use_dynamic_stride(state, dyn_state))
{
TRACE("Cannot use dynamic stride, falling back ...\n");
@ -4016,7 +4040,8 @@ VkPipeline d3d12_pipeline_state_get_pipeline(struct d3d12_pipeline_state *state,
}
VkPipeline d3d12_pipeline_state_get_or_create_pipeline(struct d3d12_pipeline_state *state,
const struct vkd3d_dynamic_state *dyn_state, const struct vkd3d_format *dsv_format,
const struct vkd3d_dynamic_state *dyn_state,
uint32_t rtv_nonnull_mask, const struct vkd3d_format *dsv_format,
const struct vkd3d_render_pass_compatibility **render_pass_compat,
uint32_t *dynamic_state_flags, uint32_t variant_flags)
{
@ -4070,6 +4095,7 @@ VkPipeline d3d12_pipeline_state_get_or_create_pipeline(struct d3d12_pipeline_sta
}
pipeline_key.dsv_format = dsv_format ? dsv_format->vk_format : VK_FORMAT_UNDEFINED;
pipeline_key.rtv_active_mask = state->graphics.rtv_active_mask & rtv_nonnull_mask;
if ((vk_pipeline = d3d12_pipeline_state_find_compiled_pipeline(state, &pipeline_key, render_pass_compat,
dynamic_state_flags)))

View File

@ -325,6 +325,7 @@ enum vkd3d_render_pass_key_flag
struct vkd3d_render_pass_key
{
uint32_t attachment_count;
uint32_t rtv_active_mask;
uint32_t flags; /* vkd3d_render_pass_key_flag */
uint32_t sample_count;
VkFormat vk_formats[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT + 1];
@ -1436,6 +1437,7 @@ struct d3d12_graphics_pipeline_state
VkPipelineColorBlendAttachmentState blend_attachments[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
unsigned int rt_count;
unsigned int null_attachment_mask;
unsigned int rtv_active_mask;
unsigned int patch_vertex_count;
const struct vkd3d_format *dsv_format;
VkFormat rtv_formats[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
@ -1554,6 +1556,7 @@ struct vkd3d_pipeline_key
D3D12_PRIMITIVE_TOPOLOGY topology;
uint32_t viewport_count;
uint32_t strides[D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
uint32_t rtv_active_mask;
VkFormat dsv_format;
bool dynamic_stride;
@ -1565,11 +1568,13 @@ bool d3d12_pipeline_state_has_replaced_shaders(struct d3d12_pipeline_state *stat
HRESULT d3d12_pipeline_state_create(struct d3d12_device *device, VkPipelineBindPoint bind_point,
const struct d3d12_pipeline_state_desc *desc, struct d3d12_pipeline_state **state);
VkPipeline d3d12_pipeline_state_get_or_create_pipeline(struct d3d12_pipeline_state *state,
const struct vkd3d_dynamic_state *dyn_state, const struct vkd3d_format *dsv_format,
const struct vkd3d_dynamic_state *dyn_state,
uint32_t rtv_nonnull_mask, const struct vkd3d_format *dsv_format,
const struct vkd3d_render_pass_compatibility **render_pass_compat,
uint32_t *dynamic_state_flags, uint32_t variant_flags);
VkPipeline d3d12_pipeline_state_get_pipeline(struct d3d12_pipeline_state *state,
const struct vkd3d_dynamic_state *dyn_state, const struct vkd3d_format *dsv_format,
const struct vkd3d_dynamic_state *dyn_state,
uint32_t rtv_nonnull_mask, const struct vkd3d_format *dsv_format,
const struct vkd3d_render_pass_compatibility **render_pass_compat,
uint32_t *dynamic_state_flags, uint32_t variant_flags);
VkPipeline d3d12_pipeline_state_create_pipeline_variant(struct d3d12_pipeline_state *state,
@ -1872,6 +1877,7 @@ struct d3d12_command_list
struct d3d12_rtv_desc rtvs[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
struct d3d12_rtv_desc dsv;
uint32_t rtv_nonnull_mask;
uint32_t dsv_plane_optimal_mask;
VkImageLayout dsv_layout;
unsigned int fb_width;