mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-04 10:29:15 +01:00
[dxvk] Optimize barrier logic
The is*Dirty methods can exit early if the resource to check is only used for reading. Only call get*Access to check for write-after-write scenarios.
This commit is contained in:
parent
11fbcd3131
commit
ad020c23f9
@ -5443,13 +5443,13 @@ namespace dxvk {
|
|||||||
const DxvkBindingInfo& binding = layout.getBinding(i, j);
|
const DxvkBindingInfo& binding = layout.getBinding(i, j);
|
||||||
const DxvkShaderResourceSlot& slot = m_rc[binding.resourceBinding];
|
const DxvkShaderResourceSlot& slot = m_rc[binding.resourceBinding];
|
||||||
|
|
||||||
DxvkAccessFlags srcAccess = 0;
|
bool requiresBarrier = false;
|
||||||
|
|
||||||
switch (binding.descriptorType) {
|
switch (binding.descriptorType) {
|
||||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
|
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
|
||||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
||||||
if (likely(slot.bufferSlice.length())) {
|
if (likely(slot.bufferSlice.length())) {
|
||||||
srcAccess = this->checkBufferBarrier<DoEmit>(slot.bufferSlice,
|
requiresBarrier = this->checkBufferBarrier<DoEmit>(slot.bufferSlice,
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, binding.access);
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, binding.access);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -5457,7 +5457,7 @@ namespace dxvk {
|
|||||||
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
|
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
|
||||||
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
|
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
|
||||||
if (likely(slot.bufferView != nullptr)) {
|
if (likely(slot.bufferView != nullptr)) {
|
||||||
srcAccess = this->checkBufferViewBarrier<DoEmit>(slot.bufferView,
|
requiresBarrier = this->checkBufferViewBarrier<DoEmit>(slot.bufferView,
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, binding.access);
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, binding.access);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -5466,7 +5466,7 @@ namespace dxvk {
|
|||||||
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
||||||
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
|
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
|
||||||
if (likely(slot.imageView != nullptr)) {
|
if (likely(slot.imageView != nullptr)) {
|
||||||
srcAccess = this->checkImageViewBarrier<DoEmit>(slot.imageView,
|
requiresBarrier = this->checkImageViewBarrier<DoEmit>(slot.imageView,
|
||||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, binding.access);
|
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, binding.access);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -5475,21 +5475,7 @@ namespace dxvk {
|
|||||||
/* nothing to do */;
|
/* nothing to do */;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DoEmit || srcAccess == 0)
|
if (requiresBarrier) {
|
||||||
continue;
|
|
||||||
|
|
||||||
// Skip write-after-write barriers if explicitly requested
|
|
||||||
DxvkAccessFlags dstAccess = DxvkBarrierSet::getAccessTypes(binding.access);
|
|
||||||
|
|
||||||
VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
|
|
||||||
| VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
|
|
||||||
|
|
||||||
if ((m_barrierControl.test(DxvkBarrierControl::IgnoreWriteAfterWrite))
|
|
||||||
&& (!(m_execBarriers.getSrcStages() & ~stageMask))
|
|
||||||
&& ((srcAccess | dstAccess) == DxvkAccess::Write))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((srcAccess | dstAccess).test(DxvkAccess::Write)) {
|
|
||||||
m_execBarriers.recordCommands(m_cmd);
|
m_execBarriers.recordCommands(m_cmd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -5520,7 +5506,7 @@ namespace dxvk {
|
|||||||
&& (slices[i]->bufferInfo().access & storageBufferAccess)) {
|
&& (slices[i]->bufferInfo().access & storageBufferAccess)) {
|
||||||
requiresBarrier = this->checkBufferBarrier<DoEmit>(*slices[i],
|
requiresBarrier = this->checkBufferBarrier<DoEmit>(*slices[i],
|
||||||
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
|
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
|
||||||
VK_ACCESS_INDIRECT_COMMAND_READ_BIT).test(DxvkAccess::Write);
|
VK_ACCESS_INDIRECT_COMMAND_READ_BIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5534,7 +5520,7 @@ namespace dxvk {
|
|||||||
&& (indexBufferSlice.bufferInfo().access & storageBufferAccess)) {
|
&& (indexBufferSlice.bufferInfo().access & storageBufferAccess)) {
|
||||||
requiresBarrier = this->checkBufferBarrier<DoEmit>(indexBufferSlice,
|
requiresBarrier = this->checkBufferBarrier<DoEmit>(indexBufferSlice,
|
||||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
||||||
VK_ACCESS_INDEX_READ_BIT).test(DxvkAccess::Write);
|
VK_ACCESS_INDEX_READ_BIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5550,7 +5536,7 @@ namespace dxvk {
|
|||||||
&& (vertexBufferSlice.bufferInfo().access & storageBufferAccess)) {
|
&& (vertexBufferSlice.bufferInfo().access & storageBufferAccess)) {
|
||||||
requiresBarrier = this->checkBufferBarrier<DoEmit>(vertexBufferSlice,
|
requiresBarrier = this->checkBufferBarrier<DoEmit>(vertexBufferSlice,
|
||||||
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
||||||
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT).test(DxvkAccess::Write);
|
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5566,14 +5552,14 @@ namespace dxvk {
|
|||||||
if (xfbBufferSlice.length()) {
|
if (xfbBufferSlice.length()) {
|
||||||
requiresBarrier = this->checkBufferBarrier<DoEmit>(xfbBufferSlice,
|
requiresBarrier = this->checkBufferBarrier<DoEmit>(xfbBufferSlice,
|
||||||
VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
|
VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
|
||||||
VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT) != 0;
|
VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT);
|
||||||
|
|
||||||
if (xfbCounterSlice.length()) {
|
if (xfbCounterSlice.length()) {
|
||||||
requiresBarrier |= this->checkBufferBarrier<DoEmit>(xfbCounterSlice,
|
requiresBarrier |= this->checkBufferBarrier<DoEmit>(xfbCounterSlice,
|
||||||
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT |
|
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT |
|
||||||
VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
|
VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
|
||||||
VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT |
|
VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT |
|
||||||
VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT) != 0;
|
VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5582,22 +5568,19 @@ namespace dxvk {
|
|||||||
// Check shader resources on every draw to handle WAW hazards
|
// Check shader resources on every draw to handle WAW hazards
|
||||||
auto layout = m_state.gp.pipeline->getBindings()->layout();
|
auto layout = m_state.gp.pipeline->getBindings()->layout();
|
||||||
|
|
||||||
for (uint32_t i = 0; i < DxvkDescriptorSets::SetCount; i++) {
|
for (uint32_t i = 0; i < DxvkDescriptorSets::SetCount && !requiresBarrier; i++) {
|
||||||
uint32_t bindingCount = layout.getBindingCount(i);
|
uint32_t bindingCount = layout.getBindingCount(i);
|
||||||
|
|
||||||
for (uint32_t j = 0; j < bindingCount && !requiresBarrier; j++) {
|
for (uint32_t j = 0; j < bindingCount && !requiresBarrier; j++) {
|
||||||
const DxvkBindingInfo& binding = layout.getBinding(i, j);
|
const DxvkBindingInfo& binding = layout.getBinding(i, j);
|
||||||
const DxvkShaderResourceSlot& slot = m_rc[binding.resourceBinding];
|
const DxvkShaderResourceSlot& slot = m_rc[binding.resourceBinding];
|
||||||
|
|
||||||
DxvkAccessFlags dstAccess = DxvkBarrierSet::getAccessTypes(binding.access);
|
|
||||||
DxvkAccessFlags srcAccess = 0;
|
|
||||||
|
|
||||||
switch (binding.descriptorType) {
|
switch (binding.descriptorType) {
|
||||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
|
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
|
||||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
||||||
if ((slot.bufferSlice.length())
|
if ((slot.bufferSlice.length())
|
||||||
&& (slot.bufferSlice.bufferInfo().access & storageBufferAccess)) {
|
&& (slot.bufferSlice.bufferInfo().access & storageBufferAccess)) {
|
||||||
srcAccess = this->checkBufferBarrier<DoEmit>(slot.bufferSlice,
|
requiresBarrier = this->checkBufferBarrier<DoEmit>(slot.bufferSlice,
|
||||||
util::pipelineStages(binding.stages), binding.access);
|
util::pipelineStages(binding.stages), binding.access);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -5606,7 +5589,7 @@ namespace dxvk {
|
|||||||
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
|
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
|
||||||
if ((slot.bufferView != nullptr)
|
if ((slot.bufferView != nullptr)
|
||||||
&& (slot.bufferView->bufferInfo().access & storageBufferAccess)) {
|
&& (slot.bufferView->bufferInfo().access & storageBufferAccess)) {
|
||||||
srcAccess = this->checkBufferViewBarrier<DoEmit>(slot.bufferView,
|
requiresBarrier = this->checkBufferViewBarrier<DoEmit>(slot.bufferView,
|
||||||
util::pipelineStages(binding.stages), binding.access);
|
util::pipelineStages(binding.stages), binding.access);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -5616,7 +5599,7 @@ namespace dxvk {
|
|||||||
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
|
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
|
||||||
if ((slot.imageView != nullptr)
|
if ((slot.imageView != nullptr)
|
||||||
&& (slot.imageView->imageInfo().access & storageImageAccess)) {
|
&& (slot.imageView->imageInfo().access & storageImageAccess)) {
|
||||||
srcAccess = this->checkImageViewBarrier<DoEmit>(slot.imageView,
|
requiresBarrier = this->checkImageViewBarrier<DoEmit>(slot.imageView,
|
||||||
util::pipelineStages(binding.stages), binding.access);
|
util::pipelineStages(binding.stages), binding.access);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -5624,16 +5607,6 @@ namespace dxvk {
|
|||||||
default:
|
default:
|
||||||
/* nothing to do */;
|
/* nothing to do */;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (srcAccess == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Skip write-after-write barriers if explicitly requested
|
|
||||||
if ((m_barrierControl.test(DxvkBarrierControl::IgnoreWriteAfterWrite))
|
|
||||||
&& ((srcAccess | dstAccess) == DxvkAccess::Write))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
requiresBarrier = (srcAccess | dstAccess).test(DxvkAccess::Write);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5646,44 +5619,61 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
template<bool DoEmit>
|
template<bool DoEmit>
|
||||||
DxvkAccessFlags DxvkContext::checkBufferBarrier(
|
bool DxvkContext::checkBufferBarrier(
|
||||||
const DxvkBufferSlice& slice,
|
const DxvkBufferSlice& bufferSlice,
|
||||||
VkPipelineStageFlags stages,
|
VkPipelineStageFlags stages,
|
||||||
VkAccessFlags access) {
|
VkAccessFlags access) {
|
||||||
if constexpr (DoEmit) {
|
if constexpr (DoEmit) {
|
||||||
m_execBarriers.accessBuffer(
|
m_execBarriers.accessBuffer(
|
||||||
slice.getSliceHandle(),
|
bufferSlice.getSliceHandle(),
|
||||||
stages, access,
|
stages, access,
|
||||||
slice.bufferInfo().stages,
|
bufferSlice.bufferInfo().stages,
|
||||||
slice.bufferInfo().access);
|
bufferSlice.bufferInfo().access);
|
||||||
return DxvkAccessFlags();
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return m_execBarriers.getBufferAccess(slice.getSliceHandle());
|
DxvkAccessFlags dstAccess = DxvkBarrierSet::getAccessTypes(access);
|
||||||
|
|
||||||
|
bool dirty = m_execBarriers.isBufferDirty(
|
||||||
|
bufferSlice.getSliceHandle(), dstAccess);
|
||||||
|
|
||||||
|
if (!dirty || dstAccess.test(DxvkAccess::Read) || !this->canIgnoreWawHazards(stages))
|
||||||
|
return dirty;
|
||||||
|
|
||||||
|
DxvkAccessFlags srcAccess = m_execBarriers.getBufferAccess(bufferSlice.getSliceHandle());
|
||||||
|
return srcAccess.test(DxvkAccess::Read);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<bool DoEmit>
|
template<bool DoEmit>
|
||||||
DxvkAccessFlags DxvkContext::checkBufferViewBarrier(
|
bool DxvkContext::checkBufferViewBarrier(
|
||||||
const Rc<DxvkBufferView>& view,
|
const Rc<DxvkBufferView>& bufferView,
|
||||||
VkPipelineStageFlags stages,
|
VkPipelineStageFlags stages,
|
||||||
VkAccessFlags access) {
|
VkAccessFlags access) {
|
||||||
if constexpr (DoEmit) {
|
if constexpr (DoEmit) {
|
||||||
m_execBarriers.accessBuffer(
|
m_execBarriers.accessBuffer(
|
||||||
view->getSliceHandle(),
|
bufferView->getSliceHandle(),
|
||||||
stages, access,
|
stages, access,
|
||||||
view->bufferInfo().stages,
|
bufferView->bufferInfo().stages,
|
||||||
view->bufferInfo().access);
|
bufferView->bufferInfo().access);
|
||||||
return DxvkAccessFlags();
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return m_execBarriers.getBufferAccess(
|
DxvkAccessFlags dstAccess = DxvkBarrierSet::getAccessTypes(access);
|
||||||
view->getSliceHandle());
|
|
||||||
|
bool dirty = m_execBarriers.isBufferDirty(
|
||||||
|
bufferView->getSliceHandle(), dstAccess);
|
||||||
|
|
||||||
|
if (!dirty || dstAccess.test(DxvkAccess::Read) || !this->canIgnoreWawHazards(stages))
|
||||||
|
return dirty;
|
||||||
|
|
||||||
|
DxvkAccessFlags srcAccess = m_execBarriers.getBufferAccess(bufferView->getSliceHandle());
|
||||||
|
return srcAccess.test(DxvkAccess::Read);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<bool DoEmit>
|
template<bool DoEmit>
|
||||||
DxvkAccessFlags DxvkContext::checkImageViewBarrier(
|
bool DxvkContext::checkImageViewBarrier(
|
||||||
const Rc<DxvkImageView>& imageView,
|
const Rc<DxvkImageView>& imageView,
|
||||||
VkPipelineStageFlags stages,
|
VkPipelineStageFlags stages,
|
||||||
VkAccessFlags access) {
|
VkAccessFlags access) {
|
||||||
@ -5696,15 +5686,38 @@ namespace dxvk {
|
|||||||
imageView->imageInfo().layout,
|
imageView->imageInfo().layout,
|
||||||
imageView->imageInfo().stages,
|
imageView->imageInfo().stages,
|
||||||
imageView->imageInfo().access);
|
imageView->imageInfo().access);
|
||||||
return DxvkAccessFlags();
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return m_execBarriers.getImageAccess(
|
DxvkAccessFlags dstAccess = DxvkBarrierSet::getAccessTypes(access);
|
||||||
|
|
||||||
|
bool dirty = m_execBarriers.isImageDirty(
|
||||||
imageView->image(),
|
imageView->image(),
|
||||||
imageView->imageSubresources());
|
imageView->imageSubresources(),
|
||||||
|
dstAccess);
|
||||||
|
|
||||||
|
if (!dirty || dstAccess.test(DxvkAccess::Read) || !this->canIgnoreWawHazards(stages))
|
||||||
|
return dirty;
|
||||||
|
|
||||||
|
DxvkAccessFlags srcAccess = m_execBarriers.getImageAccess(
|
||||||
|
imageView->image(), imageView->imageSubresources());
|
||||||
|
return srcAccess.test(DxvkAccess::Read);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DxvkContext::canIgnoreWawHazards(VkPipelineStageFlags stages) {
|
||||||
|
if (!m_barrierControl.test(DxvkBarrierControl::IgnoreWriteAfterWrite))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (stages & VK_SHADER_STAGE_COMPUTE_BIT) {
|
||||||
|
VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
|
||||||
|
return !(m_execBarriers.getSrcStages() & ~stageMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxvkContext::emitMemoryBarrier(
|
void DxvkContext::emitMemoryBarrier(
|
||||||
VkPipelineStageFlags srcStages,
|
VkPipelineStageFlags srcStages,
|
||||||
VkAccessFlags srcAccess,
|
VkAccessFlags srcAccess,
|
||||||
|
@ -1544,23 +1544,26 @@ namespace dxvk {
|
|||||||
void commitGraphicsBarriers();
|
void commitGraphicsBarriers();
|
||||||
|
|
||||||
template<bool DoEmit>
|
template<bool DoEmit>
|
||||||
DxvkAccessFlags checkBufferBarrier(
|
bool checkBufferBarrier(
|
||||||
const DxvkBufferSlice& slice,
|
const DxvkBufferSlice& bufferSlice,
|
||||||
VkPipelineStageFlags stages,
|
VkPipelineStageFlags stages,
|
||||||
VkAccessFlags access);
|
VkAccessFlags access);
|
||||||
|
|
||||||
template<bool DoEmit>
|
template<bool DoEmit>
|
||||||
DxvkAccessFlags checkBufferViewBarrier(
|
bool checkBufferViewBarrier(
|
||||||
const Rc<DxvkBufferView>& slice,
|
const Rc<DxvkBufferView>& bufferView,
|
||||||
VkPipelineStageFlags stages,
|
VkPipelineStageFlags stages,
|
||||||
VkAccessFlags access);
|
VkAccessFlags access);
|
||||||
|
|
||||||
template<bool DoEmit>
|
template<bool DoEmit>
|
||||||
DxvkAccessFlags checkImageViewBarrier(
|
bool checkImageViewBarrier(
|
||||||
const Rc<DxvkImageView>& imageView,
|
const Rc<DxvkImageView>& imageView,
|
||||||
VkPipelineStageFlags stages,
|
VkPipelineStageFlags stages,
|
||||||
VkAccessFlags access);
|
VkAccessFlags access);
|
||||||
|
|
||||||
|
bool canIgnoreWawHazards(
|
||||||
|
VkPipelineStageFlags stages);
|
||||||
|
|
||||||
void emitMemoryBarrier(
|
void emitMemoryBarrier(
|
||||||
VkPipelineStageFlags srcStages,
|
VkPipelineStageFlags srcStages,
|
||||||
VkAccessFlags srcAccess,
|
VkAccessFlags srcAccess,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user