vkd3d: Add support for multiplanar depth/stencil state transitions.

If separate transitions of the depth and stencil plane occur in the
same array of barriers, they will be consolidated into one Vulkan
layout transition. This can only be supported for combinations of
depth read and depth write states, or identical states.

Signed-off-by: Conor McCarthy <cmccarthy@codeweavers.com>
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Conor McCarthy 2019-10-24 22:20:49 +10:00 committed by Alexandre Julliard
parent 907d733ffe
commit 2155748c41

View File

@ -1872,7 +1872,7 @@ static void d3d12_command_list_invalidate_bindings(struct d3d12_command_list *li
} }
} }
static bool vk_barrier_parameters_from_d3d12_resource_state(unsigned int state, static bool vk_barrier_parameters_from_d3d12_resource_state(unsigned int state, unsigned int stencil_state,
const struct d3d12_resource *resource, VkQueueFlags vk_queue_flags, const struct vkd3d_vulkan_info *vk_info, const struct d3d12_resource *resource, VkQueueFlags vk_queue_flags, const struct vkd3d_vulkan_info *vk_info,
VkAccessFlags *access_mask, VkPipelineStageFlags *stage_flags, VkImageLayout *image_layout) VkAccessFlags *access_mask, VkPipelineStageFlags *stage_flags, VkImageLayout *image_layout)
{ {
@ -1911,7 +1911,7 @@ static bool vk_barrier_parameters_from_d3d12_resource_state(unsigned int state,
} }
else if (resource->present_state != D3D12_RESOURCE_STATE_COMMON) else if (resource->present_state != D3D12_RESOURCE_STATE_COMMON)
{ {
vk_barrier_parameters_from_d3d12_resource_state(resource->present_state, vk_barrier_parameters_from_d3d12_resource_state(resource->present_state, 0,
resource, vk_queue_flags, vk_info, access_mask, stage_flags, image_layout); resource, vk_queue_flags, vk_info, access_mask, stage_flags, image_layout);
return true; return true;
} }
@ -1945,7 +1945,12 @@ static bool vk_barrier_parameters_from_d3d12_resource_state(unsigned int state,
*stage_flags = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT *stage_flags = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
if (image_layout) if (image_layout)
*image_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; {
if (!stencil_state || (stencil_state & D3D12_RESOURCE_STATE_DEPTH_WRITE))
*image_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
else
*image_layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL;
}
return true; return true;
case D3D12_RESOURCE_STATE_COPY_DEST: case D3D12_RESOURCE_STATE_COPY_DEST:
@ -1975,7 +1980,17 @@ static bool vk_barrier_parameters_from_d3d12_resource_state(unsigned int state,
*access_mask = 0; *access_mask = 0;
*stage_flags = 0; *stage_flags = 0;
if (image_layout) if (image_layout)
*image_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; {
if (stencil_state & D3D12_RESOURCE_STATE_DEPTH_WRITE)
{
*image_layout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL;
*access_mask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
}
else
{
*image_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
}
}
break; break;
case D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE: case D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE:
@ -2096,7 +2111,7 @@ static void d3d12_command_list_transition_resource_to_initial_state(struct d3d12
barrier.oldLayout = d3d12_resource_is_cpu_accessible(resource) ? barrier.oldLayout = d3d12_resource_is_cpu_accessible(resource) ?
VK_IMAGE_LAYOUT_PREINITIALIZED : VK_IMAGE_LAYOUT_UNDEFINED; VK_IMAGE_LAYOUT_PREINITIALIZED : VK_IMAGE_LAYOUT_UNDEFINED;
if (!vk_barrier_parameters_from_d3d12_resource_state(resource->initial_state, if (!vk_barrier_parameters_from_d3d12_resource_state(resource->initial_state, 0,
resource, list->vk_queue_flags, vk_info, &barrier.dstAccessMask, &dst_stage_mask, &barrier.newLayout)) resource, list->vk_queue_flags, vk_info, &barrier.dstAccessMask, &dst_stage_mask, &barrier.newLayout))
{ {
FIXME("Unhandled state %#x.\n", resource->initial_state); FIXME("Unhandled state %#x.\n", resource->initial_state);
@ -3710,6 +3725,44 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetPipelineState(ID3D12Graphics
list->state = state; list->state = state;
} }
static bool is_ds_multiplanar_resolvable(unsigned int first_state, unsigned int second_state)
{
/* Only combinations of depth/stencil read/write are supported. */
return first_state == second_state
|| ((first_state & (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_DEPTH_WRITE))
&& (second_state & (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_DEPTH_WRITE)));
}
static unsigned int d3d12_find_ds_multiplanar_transition(const D3D12_RESOURCE_BARRIER *barriers,
unsigned int i, unsigned int barrier_count, unsigned int sub_resource_count)
{
unsigned int sub_resource_idx = barriers[i].u.Transition.Subresource;
unsigned int j;
for (j = i + 1; j < barrier_count; ++j)
{
if (barriers[j].Type == D3D12_RESOURCE_BARRIER_TYPE_TRANSITION
&& barriers[j].u.Transition.pResource == barriers[i].u.Transition.pResource
&& sub_resource_idx % sub_resource_count == barriers[j].u.Transition.Subresource % sub_resource_count)
{
/* Second barrier must be for a different plane. */
if (barriers[j].u.Transition.Subresource == sub_resource_idx)
return 0;
/* Validate the second barrier and check if the combination of two states is supported. */
if (!is_valid_resource_state(barriers[j].u.Transition.StateBefore)
|| !is_ds_multiplanar_resolvable(barriers[i].u.Transition.StateBefore, barriers[j].u.Transition.StateBefore)
|| !is_valid_resource_state(barriers[j].u.Transition.StateAfter)
|| !is_ds_multiplanar_resolvable(barriers[i].u.Transition.StateAfter, barriers[j].u.Transition.StateAfter)
|| barriers[j].u.Transition.Subresource >= sub_resource_count * 2u)
return 0;
return j;
}
}
return 0;
}
static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsCommandList1 *iface, static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsCommandList1 *iface,
UINT barrier_count, const D3D12_RESOURCE_BARRIER *barriers) UINT barrier_count, const D3D12_RESOURCE_BARRIER *barriers)
{ {
@ -3717,6 +3770,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsC
bool have_aliasing_barriers = false, have_split_barriers = false; bool have_aliasing_barriers = false, have_split_barriers = false;
const struct vkd3d_vk_device_procs *vk_procs; const struct vkd3d_vk_device_procs *vk_procs;
const struct vkd3d_vulkan_info *vk_info; const struct vkd3d_vulkan_info *vk_info;
bool *multiplanar_handled = NULL;
unsigned int i; unsigned int i;
TRACE("iface %p, barrier_count %u, barriers %p.\n", iface, barrier_count, barriers); TRACE("iface %p, barrier_count %u, barriers %p.\n", iface, barrier_count, barriers);
@ -3746,6 +3800,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsC
{ {
case D3D12_RESOURCE_BARRIER_TYPE_TRANSITION: case D3D12_RESOURCE_BARRIER_TYPE_TRANSITION:
{ {
unsigned int state_before, state_after, stencil_state_before = 0, stencil_state_after = 0;
const D3D12_RESOURCE_TRANSITION_BARRIER *transition = &current->u.Transition; const D3D12_RESOURCE_TRANSITION_BARRIER *transition = &current->u.Transition;
if (!is_valid_resource_state(transition->StateBefore)) if (!is_valid_resource_state(transition->StateBefore))
@ -3767,18 +3822,55 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsC
continue; continue;
} }
if (multiplanar_handled && multiplanar_handled[i])
continue;
state_before = transition->StateBefore;
state_after = transition->StateAfter;
sub_resource_idx = transition->Subresource; sub_resource_idx = transition->Subresource;
if (!vk_barrier_parameters_from_d3d12_resource_state(transition->StateBefore, if (sub_resource_idx != D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES
&& (resource->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL))
{
unsigned int sub_resource_count = d3d12_resource_desc_get_sub_resource_count(&resource->desc);
unsigned int j = d3d12_find_ds_multiplanar_transition(barriers, i, barrier_count, sub_resource_count);
if (j && (multiplanar_handled || (multiplanar_handled = vkd3d_calloc(barrier_count, sizeof(*multiplanar_handled)))))
{
multiplanar_handled[j] = true;
if (sub_resource_idx >= sub_resource_count)
{
sub_resource_idx -= sub_resource_count;
/* The stencil barrier is at i, depth at j. */
state_before = barriers[j].u.Transition.StateBefore;
state_after = barriers[j].u.Transition.StateAfter;
stencil_state_before = transition->StateBefore;
stencil_state_after = transition->StateAfter;
}
else
{
/* Depth at i, stencil at j. */
stencil_state_before = barriers[j].u.Transition.StateBefore;
stencil_state_after = barriers[j].u.Transition.StateAfter;
}
}
else if (sub_resource_idx >= sub_resource_count)
{
FIXME_ONCE("Unhandled sub-resource idx %u.\n", sub_resource_idx);
continue;
}
}
if (!vk_barrier_parameters_from_d3d12_resource_state(state_before, stencil_state_before,
resource, list->vk_queue_flags, vk_info, &src_access_mask, &src_stage_mask, &layout_before)) resource, list->vk_queue_flags, vk_info, &src_access_mask, &src_stage_mask, &layout_before))
{ {
FIXME("Unhandled state %#x.\n", transition->StateBefore); FIXME("Unhandled state %#x.\n", state_before);
continue; continue;
} }
if (!vk_barrier_parameters_from_d3d12_resource_state(transition->StateAfter, if (!vk_barrier_parameters_from_d3d12_resource_state(state_after, stencil_state_after,
resource, list->vk_queue_flags, vk_info, &dst_access_mask, &dst_stage_mask, &layout_after)) resource, list->vk_queue_flags, vk_info, &dst_access_mask, &dst_stage_mask, &layout_after))
{ {
FIXME("Unhandled state %#x.\n", transition->StateAfter); FIXME("Unhandled state %#x.\n", state_after);
continue; continue;
} }
@ -3795,7 +3887,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsC
VkAccessFlags access_mask; VkAccessFlags access_mask;
resource = unsafe_impl_from_ID3D12Resource(uav->pResource); resource = unsafe_impl_from_ID3D12Resource(uav->pResource);
vk_barrier_parameters_from_d3d12_resource_state(D3D12_RESOURCE_STATE_UNORDERED_ACCESS, vk_barrier_parameters_from_d3d12_resource_state(D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0,
resource, list->vk_queue_flags, vk_info, &access_mask, &stage_mask, &image_layout); resource, list->vk_queue_flags, vk_info, &access_mask, &stage_mask, &image_layout);
src_access_mask = dst_access_mask = access_mask; src_access_mask = dst_access_mask = access_mask;
src_stage_mask = dst_stage_mask = stage_mask; src_stage_mask = dst_stage_mask = stage_mask;
@ -3894,6 +3986,8 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsC
} }
} }
vkd3d_free(multiplanar_handled);
if (have_aliasing_barriers) if (have_aliasing_barriers)
FIXME_ONCE("Aliasing barriers not implemented yet.\n"); FIXME_ONCE("Aliasing barriers not implemented yet.\n");
@ -4737,7 +4831,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewUint(ID
buffer_barrier.offset = cpu_descriptor->uav.buffer.offset; buffer_barrier.offset = cpu_descriptor->uav.buffer.offset;
buffer_barrier.size = cpu_descriptor->uav.buffer.size; buffer_barrier.size = cpu_descriptor->uav.buffer.size;
vk_barrier_parameters_from_d3d12_resource_state(D3D12_RESOURCE_STATE_UNORDERED_ACCESS, vk_barrier_parameters_from_d3d12_resource_state(D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0,
resource_impl, list->vk_queue_flags, vk_info, &buffer_barrier.dstAccessMask, &stage_mask, NULL); resource_impl, list->vk_queue_flags, vk_info, &buffer_barrier.dstAccessMask, &stage_mask, NULL);
VK_CALL(vkCmdPipelineBarrier(list->vk_command_buffer, VK_CALL(vkCmdPipelineBarrier(list->vk_command_buffer,
@ -4770,7 +4864,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewUint(ID
image_barrier.image = resource_impl->u.vk_image; image_barrier.image = resource_impl->u.vk_image;
image_barrier.subresourceRange = range; image_barrier.subresourceRange = range;
vk_barrier_parameters_from_d3d12_resource_state(D3D12_RESOURCE_STATE_UNORDERED_ACCESS, vk_barrier_parameters_from_d3d12_resource_state(D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0,
resource_impl, list->vk_queue_flags, vk_info, &image_barrier.dstAccessMask, &stage_mask, NULL); resource_impl, list->vk_queue_flags, vk_info, &image_barrier.dstAccessMask, &stage_mask, NULL);
VK_CALL(vkCmdPipelineBarrier(list->vk_command_buffer, VK_CALL(vkCmdPipelineBarrier(list->vk_command_buffer,