mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 03:16:54 +02:00
137 lines
5.7 KiB
C++
137 lines
5.7 KiB
C++
#include "graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.h"
|
|
|
|
#include "common/assert.h"
|
|
#include "graphics/shader/shader.h"
|
|
#include "graphics/shader/shaderBindings.h"
|
|
|
|
#include <cstring>
|
|
|
|
namespace Libs::Graphics {
|
|
|
|
vk::ShaderStageFlagBits NativeShaderStage(ShaderType stage) {
|
|
switch (stage) {
|
|
case ShaderType::Local:
|
|
case ShaderType::Vertex: return vk::ShaderStageFlagBits::eVertex;
|
|
case ShaderType::Mesh: return vk::ShaderStageFlagBits::eMeshEXT;
|
|
case ShaderType::TessellationControl: return vk::ShaderStageFlagBits::eTessellationControl;
|
|
case ShaderType::TessellationEvaluation:
|
|
return vk::ShaderStageFlagBits::eTessellationEvaluation;
|
|
case ShaderType::Pixel: return vk::ShaderStageFlagBits::eFragment;
|
|
case ShaderType::Compute: return vk::ShaderStageFlagBits::eCompute;
|
|
default: EXIT("unknown native shader stage\n");
|
|
}
|
|
}
|
|
|
|
vk::PipelineStageFlags ShaderPipelineStages(vk::ShaderStageFlags stages) {
|
|
vk::PipelineStageFlags result = {};
|
|
if (stages & vk::ShaderStageFlagBits::eVertex) {
|
|
result |= vk::PipelineStageFlagBits::eVertexShader;
|
|
}
|
|
if (stages & vk::ShaderStageFlagBits::eMeshEXT) {
|
|
result |= vk::PipelineStageFlagBits::eMeshShaderEXT;
|
|
}
|
|
if (stages & vk::ShaderStageFlagBits::eTessellationControl) {
|
|
result |= vk::PipelineStageFlagBits::eTessellationControlShader;
|
|
}
|
|
if (stages & vk::ShaderStageFlagBits::eTessellationEvaluation) {
|
|
result |= vk::PipelineStageFlagBits::eTessellationEvaluationShader;
|
|
}
|
|
if (stages & vk::ShaderStageFlagBits::eFragment) {
|
|
result |= vk::PipelineStageFlagBits::eFragmentShader;
|
|
}
|
|
if (stages & vk::ShaderStageFlagBits::eCompute) {
|
|
result |= vk::PipelineStageFlagBits::eComputeShader;
|
|
}
|
|
EXIT_IF(!result);
|
|
return result;
|
|
}
|
|
|
|
VulkanMemoryBarrier MakeShaderWriteDependency() {
|
|
VulkanMemoryBarrier barrier {};
|
|
barrier.srcAccessMask = vk::AccessFlagBits::eShaderWrite;
|
|
barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite |
|
|
vk::AccessFlagBits::eVertexAttributeRead |
|
|
vk::AccessFlagBits::eIndexRead | vk::AccessFlagBits::eUniformRead |
|
|
vk::AccessFlagBits::eTransferRead | vk::AccessFlagBits::eTransferWrite |
|
|
vk::AccessFlagBits::eColorAttachmentRead |
|
|
vk::AccessFlagBits::eColorAttachmentWrite;
|
|
return barrier;
|
|
}
|
|
|
|
VulkanMemoryBarrier MakeShaderAccessDependency() {
|
|
VulkanMemoryBarrier barrier {};
|
|
barrier.srcAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite;
|
|
barrier.dstAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite;
|
|
return barrier;
|
|
}
|
|
|
|
VulkanMemoryBarrier MakeShaderWriteHazardDependency() {
|
|
VulkanMemoryBarrier barrier {};
|
|
barrier.srcAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite;
|
|
barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite;
|
|
return barrier;
|
|
}
|
|
|
|
vk::BufferMemoryBarrier MakeGdsDependency(vk::Buffer buffer) {
|
|
EXIT_IF(buffer == nullptr);
|
|
|
|
vk::BufferMemoryBarrier barrier {};
|
|
barrier.srcAccessMask = vk::AccessFlagBits::eHostWrite | vk::AccessFlagBits::eTransferWrite |
|
|
vk::AccessFlagBits::eShaderWrite;
|
|
barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite;
|
|
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
barrier.buffer = buffer;
|
|
barrier.offset = 0;
|
|
barrier.size = VK_WHOLE_SIZE;
|
|
return barrier;
|
|
}
|
|
|
|
bool HasShaderBufferWrites(const ShaderStageRuntime& runtime) {
|
|
EXIT_IF(!runtime);
|
|
const auto& program = *runtime.program;
|
|
const auto& resources = runtime.resources;
|
|
EXIT_IF(resources.buffers.size() != program.info.buffers.size());
|
|
bool has_writes = false;
|
|
for (uint32_t i = 0; i < program.info.buffers.size(); i++) {
|
|
if (!program.info.buffers[i].written) {
|
|
continue;
|
|
}
|
|
const auto& value = resources.buffers[i];
|
|
EXIT_IF(value.dword_count < 4);
|
|
ShaderBufferResource descriptor;
|
|
std::memcpy(descriptor.fields, value.dwords.data(), sizeof(descriptor.fields));
|
|
// A zero stride means byte addressing. For either addressing mode a nonzero record
|
|
// count is exactly the condition for a nonempty descriptor range.
|
|
has_writes |= descriptor.Base48() != 0 && descriptor.NumRecords() != 0;
|
|
}
|
|
return has_writes;
|
|
}
|
|
|
|
void ShaderAccessBarrier(vk::CommandBuffer vk_buffer, vk::PipelineStageFlags source_stages) {
|
|
EXIT_IF(vk_buffer == nullptr || !source_stages);
|
|
const auto barrier = MakeShaderAccessDependency();
|
|
vk_buffer.pipelineBarrier(source_stages, vk::PipelineStageFlagBits::eAllCommands,
|
|
vk::DependencyFlags {}, 1, &barrier, 0, nullptr, 0, nullptr);
|
|
}
|
|
|
|
void ShaderWriteHazardBarrier(vk::CommandBuffer vk_buffer,
|
|
vk::PipelineStageFlags destination_stages) {
|
|
EXIT_IF(vk_buffer == nullptr || !destination_stages);
|
|
const auto barrier = MakeShaderWriteHazardDependency();
|
|
vk_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, destination_stages,
|
|
vk::DependencyFlags {}, 1, &barrier, 0, nullptr, 0, nullptr);
|
|
}
|
|
|
|
void ShaderWriteBarrier(vk::CommandBuffer vk_buffer, vk::PipelineStageFlags source_stages) {
|
|
EXIT_IF(vk_buffer == nullptr || !source_stages);
|
|
const auto barrier = MakeShaderWriteDependency();
|
|
vk_buffer.pipelineBarrier(source_stages,
|
|
vk::PipelineStageFlagBits::eComputeShader |
|
|
vk::PipelineStageFlagBits::eAllGraphics |
|
|
vk::PipelineStageFlagBits::eTransfer,
|
|
vk::DependencyFlags {}, 1, &barrier, 0, nullptr, 0, nullptr);
|
|
}
|
|
|
|
} // namespace Libs::Graphics
|