mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-12-10 13:48:40 +00:00
video_core: Add image support
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
|
||||
namespace Vulkan::LiverpoolToVK {
|
||||
|
||||
using DepthBuffer = Liverpool::DepthBuffer;
|
||||
|
||||
vk::StencilOp StencilOp(Liverpool::StencilFunc op) {
|
||||
switch (op) {
|
||||
case Liverpool::StencilFunc::Keep:
|
||||
@@ -77,6 +79,8 @@ vk::PrimitiveTopology PrimitiveType(Liverpool::PrimitiveType type) {
|
||||
case Liverpool::PrimitiveType::QuadList:
|
||||
// Needs to generate index buffer on the fly.
|
||||
return vk::PrimitiveTopology::eTriangleList;
|
||||
case Liverpool::PrimitiveType::RectList:
|
||||
return vk::PrimitiveTopology::eTriangleList;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return vk::PrimitiveTopology::eTriangleList;
|
||||
@@ -113,6 +117,161 @@ vk::CullModeFlags CullMode(Liverpool::CullMode mode) {
|
||||
}
|
||||
}
|
||||
|
||||
vk::BlendFactor BlendFactor(Liverpool::BlendControl::BlendFactor factor) {
|
||||
using BlendFactor = Liverpool::BlendControl::BlendFactor;
|
||||
switch (factor) {
|
||||
case BlendFactor::Zero:
|
||||
return vk::BlendFactor::eZero;
|
||||
case BlendFactor::One:
|
||||
return vk::BlendFactor::eOne;
|
||||
case BlendFactor::SrcColor:
|
||||
return vk::BlendFactor::eSrcColor;
|
||||
case BlendFactor::OneMinusSrcColor:
|
||||
return vk::BlendFactor::eOneMinusSrcColor;
|
||||
case BlendFactor::SrcAlpha:
|
||||
return vk::BlendFactor::eSrcAlpha;
|
||||
case BlendFactor::OneMinusSrcAlpha:
|
||||
return vk::BlendFactor::eOneMinusSrcAlpha;
|
||||
case BlendFactor::DstAlpha:
|
||||
return vk::BlendFactor::eDstAlpha;
|
||||
case BlendFactor::OneMinusDstAlpha:
|
||||
return vk::BlendFactor::eOneMinusDstAlpha;
|
||||
case BlendFactor::DstColor:
|
||||
return vk::BlendFactor::eDstColor;
|
||||
case BlendFactor::OneMinusDstColor:
|
||||
return vk::BlendFactor::eOneMinusDstColor;
|
||||
case BlendFactor::SrcAlphaSaturate:
|
||||
return vk::BlendFactor::eSrcAlphaSaturate;
|
||||
case BlendFactor::ConstantColor:
|
||||
return vk::BlendFactor::eConstantColor;
|
||||
case BlendFactor::OneMinusConstantColor:
|
||||
return vk::BlendFactor::eOneMinusConstantColor;
|
||||
case BlendFactor::Src1Color:
|
||||
return vk::BlendFactor::eSrc1Color;
|
||||
case BlendFactor::InvSrc1Color:
|
||||
return vk::BlendFactor::eOneMinusSrc1Color;
|
||||
case BlendFactor::Src1Alpha:
|
||||
return vk::BlendFactor::eSrc1Alpha;
|
||||
case BlendFactor::InvSrc1Alpha:
|
||||
return vk::BlendFactor::eOneMinusSrc1Alpha;
|
||||
case BlendFactor::ConstantAlpha:
|
||||
return vk::BlendFactor::eConstantAlpha;
|
||||
case BlendFactor::OneMinusConstantAlpha:
|
||||
return vk::BlendFactor::eOneMinusConstantAlpha;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
vk::BlendOp BlendOp(Liverpool::BlendControl::BlendFunc func) {
|
||||
using BlendFunc = Liverpool::BlendControl::BlendFunc;
|
||||
switch (func) {
|
||||
case BlendFunc::Add:
|
||||
return vk::BlendOp::eAdd;
|
||||
case BlendFunc::Subtract:
|
||||
return vk::BlendOp::eSubtract;
|
||||
case BlendFunc::Min:
|
||||
return vk::BlendOp::eMin;
|
||||
case BlendFunc::Max:
|
||||
return vk::BlendOp::eMax;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/chaotic-cx/mesa-mirror/blob/0954afff5/src/amd/vulkan/radv_sampler.c#L21
|
||||
vk::SamplerAddressMode ClampMode(AmdGpu::ClampMode mode) {
|
||||
switch (mode) {
|
||||
case AmdGpu::ClampMode::Wrap:
|
||||
return vk::SamplerAddressMode::eRepeat;
|
||||
case AmdGpu::ClampMode::Mirror:
|
||||
return vk::SamplerAddressMode::eMirroredRepeat;
|
||||
case AmdGpu::ClampMode::ClampLastTexel:
|
||||
return vk::SamplerAddressMode::eClampToEdge;
|
||||
case AmdGpu::ClampMode::MirrorOnceLastTexel:
|
||||
return vk::SamplerAddressMode::eMirrorClampToEdge;
|
||||
case AmdGpu::ClampMode::ClampBorder:
|
||||
return vk::SamplerAddressMode::eClampToBorder;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
vk::CompareOp DepthCompare(AmdGpu::DepthCompare comp) {
|
||||
switch (comp) {
|
||||
case AmdGpu::DepthCompare::Never:
|
||||
return vk::CompareOp::eNever;
|
||||
case AmdGpu::DepthCompare::Less:
|
||||
return vk::CompareOp::eLess;
|
||||
case AmdGpu::DepthCompare::Equal:
|
||||
return vk::CompareOp::eEqual;
|
||||
case AmdGpu::DepthCompare::LessEqual:
|
||||
return vk::CompareOp::eLessOrEqual;
|
||||
case AmdGpu::DepthCompare::Greater:
|
||||
return vk::CompareOp::eGreater;
|
||||
case AmdGpu::DepthCompare::NotEqual:
|
||||
return vk::CompareOp::eNotEqual;
|
||||
case AmdGpu::DepthCompare::GreaterEqual:
|
||||
return vk::CompareOp::eGreaterOrEqual;
|
||||
case AmdGpu::DepthCompare::Always:
|
||||
return vk::CompareOp::eAlways;
|
||||
}
|
||||
}
|
||||
|
||||
vk::Filter Filter(AmdGpu::Filter filter) {
|
||||
switch (filter) {
|
||||
case AmdGpu::Filter::Point:
|
||||
case AmdGpu::Filter::AnisoPoint:
|
||||
return vk::Filter::eNearest;
|
||||
case AmdGpu::Filter::Bilinear:
|
||||
case AmdGpu::Filter::AnisoLinear:
|
||||
return vk::Filter::eLinear;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
vk::SamplerReductionMode FilterMode(AmdGpu::FilterMode mode) {
|
||||
switch (mode) {
|
||||
case AmdGpu::FilterMode::Blend:
|
||||
return vk::SamplerReductionMode::eWeightedAverage;
|
||||
case AmdGpu::FilterMode::Min:
|
||||
return vk::SamplerReductionMode::eMin;
|
||||
case AmdGpu::FilterMode::Max:
|
||||
return vk::SamplerReductionMode::eMax;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
vk::SamplerMipmapMode MipFilter(AmdGpu::MipFilter filter) {
|
||||
switch (filter) {
|
||||
case AmdGpu::MipFilter::Point:
|
||||
return vk::SamplerMipmapMode::eNearest;
|
||||
case AmdGpu::MipFilter::Linear:
|
||||
return vk::SamplerMipmapMode::eLinear;
|
||||
case AmdGpu::MipFilter::None:
|
||||
return vk::SamplerMipmapMode::eNearest;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
vk::BorderColor BorderColor(AmdGpu::BorderColor color) {
|
||||
switch (color) {
|
||||
case AmdGpu::BorderColor::OpaqueBlack:
|
||||
return vk::BorderColor::eFloatOpaqueBlack;
|
||||
case AmdGpu::BorderColor::TransparentBlack:
|
||||
return vk::BorderColor::eFloatTransparentBlack;
|
||||
case AmdGpu::BorderColor::White:
|
||||
return vk::BorderColor::eFloatOpaqueWhite;
|
||||
case AmdGpu::BorderColor::Custom:
|
||||
return vk::BorderColor::eFloatCustomEXT;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
vk::Format SurfaceFormat(AmdGpu::DataFormat data_format, AmdGpu::NumberFormat num_format) {
|
||||
if (data_format == AmdGpu::DataFormat::Format32_32_32_32 &&
|
||||
num_format == AmdGpu::NumberFormat::Float) {
|
||||
@@ -130,11 +289,22 @@ vk::Format SurfaceFormat(AmdGpu::DataFormat data_format, AmdGpu::NumberFormat nu
|
||||
num_format == AmdGpu::NumberFormat::Srgb) {
|
||||
return vk::Format::eR8G8B8A8Srgb;
|
||||
}
|
||||
if (data_format == AmdGpu::DataFormat::Format32_32_32 &&
|
||||
num_format == AmdGpu::NumberFormat::Float) {
|
||||
return vk::Format::eR32G32B32Sfloat;
|
||||
}
|
||||
if (data_format == AmdGpu::DataFormat::Format32_32 &&
|
||||
num_format == AmdGpu::NumberFormat::Float) {
|
||||
return vk::Format::eR32G32Sfloat;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
vk::Format DepthFormat(Liverpool::DepthBuffer::ZFormat z_format,
|
||||
Liverpool::DepthBuffer::StencilFormat stencil_format) {
|
||||
vk::Format DepthFormat(DepthBuffer::ZFormat z_format, DepthBuffer::StencilFormat stencil_format) {
|
||||
if (z_format == DepthBuffer::ZFormat::Z32Float &&
|
||||
stencil_format == DepthBuffer::StencilFormat::Stencil8) {
|
||||
return vk::Format::eD32SfloatS8Uint;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "video_core/amdgpu/liverpool.h"
|
||||
#include "video_core/amdgpu/pixel_format.h"
|
||||
#include "video_core/amdgpu/resource.h"
|
||||
#include "video_core/renderer_vulkan/vk_common.h"
|
||||
|
||||
namespace Vulkan::LiverpoolToVK {
|
||||
@@ -21,6 +22,22 @@ vk::PolygonMode PolygonMode(Liverpool::PolygonMode mode);
|
||||
|
||||
vk::CullModeFlags CullMode(Liverpool::CullMode mode);
|
||||
|
||||
vk::BlendFactor BlendFactor(Liverpool::BlendControl::BlendFactor factor);
|
||||
|
||||
vk::BlendOp BlendOp(Liverpool::BlendControl::BlendFunc func);
|
||||
|
||||
vk::SamplerAddressMode ClampMode(AmdGpu::ClampMode mode);
|
||||
|
||||
vk::CompareOp DepthCompare(AmdGpu::DepthCompare comp);
|
||||
|
||||
vk::Filter Filter(AmdGpu::Filter filter);
|
||||
|
||||
vk::SamplerReductionMode FilterMode(AmdGpu::FilterMode mode);
|
||||
|
||||
vk::SamplerMipmapMode MipFilter(AmdGpu::MipFilter filter);
|
||||
|
||||
vk::BorderColor BorderColor(AmdGpu::BorderColor color);
|
||||
|
||||
vk::Format SurfaceFormat(AmdGpu::DataFormat data_format, AmdGpu::NumberFormat num_format);
|
||||
|
||||
vk::Format DepthFormat(Liverpool::DepthBuffer::ZFormat z_format,
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||
#include "video_core/renderer_vulkan/vk_stream_buffer.h"
|
||||
#include "video_core/texture_cache/texture_cache.h"
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
@@ -25,8 +27,7 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||
}
|
||||
stages[i] = *infos[i];
|
||||
}
|
||||
|
||||
desc_layout = BuildSetLayout();
|
||||
BuildDescSetLayout();
|
||||
const vk::DescriptorSetLayout set_layout = *desc_layout;
|
||||
const vk::PipelineLayoutCreateInfo layout_info = {
|
||||
.setLayoutCount = 1U,
|
||||
@@ -81,20 +82,6 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||
.sampleShadingEnable = false,
|
||||
};
|
||||
|
||||
const vk::PipelineColorBlendAttachmentState colorblend_attachment = {
|
||||
.blendEnable = false,
|
||||
.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
|
||||
vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA,
|
||||
};
|
||||
|
||||
const vk::PipelineColorBlendStateCreateInfo color_blending = {
|
||||
.logicOpEnable = false,
|
||||
.logicOp = vk::LogicOp::eCopy,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = &colorblend_attachment,
|
||||
.blendConstants = std::array{1.0f, 1.0f, 1.0f, 1.0f},
|
||||
};
|
||||
|
||||
const vk::Viewport viewport = {
|
||||
.x = 0.0f,
|
||||
.y = 0.0f,
|
||||
@@ -119,6 +106,7 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||
boost::container::static_vector<vk::DynamicState, 14> dynamic_states = {
|
||||
vk::DynamicState::eViewport,
|
||||
vk::DynamicState::eScissor,
|
||||
vk::DynamicState::eBlendConstants,
|
||||
};
|
||||
|
||||
const vk::PipelineDynamicStateCreateInfo dynamic_info = {
|
||||
@@ -174,6 +162,30 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||
.stencilAttachmentFormat = vk::Format::eUndefined,
|
||||
};
|
||||
|
||||
std::array<vk::PipelineColorBlendAttachmentState, Liverpool::NumColorBuffers> attachments;
|
||||
for (u32 i = 0; i < num_color_formats; i++) {
|
||||
const auto& control = key.blend_controls[i];
|
||||
attachments[i] = vk::PipelineColorBlendAttachmentState{
|
||||
.blendEnable = key.blend_controls[i].enable,
|
||||
.srcColorBlendFactor = LiverpoolToVK::BlendFactor(control.color_src_factor),
|
||||
.dstColorBlendFactor = LiverpoolToVK::BlendFactor(control.color_dst_factor),
|
||||
.colorBlendOp = LiverpoolToVK::BlendOp(control.color_func),
|
||||
.srcAlphaBlendFactor = LiverpoolToVK::BlendFactor(control.alpha_src_factor),
|
||||
.dstAlphaBlendFactor = LiverpoolToVK::BlendFactor(control.color_dst_factor),
|
||||
.alphaBlendOp = LiverpoolToVK::BlendOp(control.alpha_func),
|
||||
.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
|
||||
vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA,
|
||||
};
|
||||
}
|
||||
|
||||
const vk::PipelineColorBlendStateCreateInfo color_blending = {
|
||||
.logicOpEnable = false,
|
||||
.logicOp = vk::LogicOp::eCopy,
|
||||
.attachmentCount = num_color_formats,
|
||||
.pAttachments = attachments.data(),
|
||||
.blendConstants = std::array{1.0f, 1.0f, 1.0f, 1.0f},
|
||||
};
|
||||
|
||||
const vk::GraphicsPipelineCreateInfo pipeline_info = {
|
||||
.pNext = &pipeline_rendering_ci,
|
||||
.stageCount = shader_count,
|
||||
@@ -199,14 +211,31 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
||||
|
||||
GraphicsPipeline::~GraphicsPipeline() = default;
|
||||
|
||||
vk::UniqueDescriptorSetLayout GraphicsPipeline::BuildSetLayout() const {
|
||||
void GraphicsPipeline::BuildDescSetLayout() {
|
||||
u32 binding{};
|
||||
boost::container::small_vector<vk::DescriptorSetLayoutBinding, 32> bindings;
|
||||
for (const auto& stage : stages) {
|
||||
for (const auto& buffer : stage.buffers) {
|
||||
bindings.push_back({
|
||||
.binding = binding++,
|
||||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||
.descriptorType = buffer.is_storage ? vk::DescriptorType::eStorageBuffer
|
||||
: vk::DescriptorType::eUniformBuffer,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
|
||||
});
|
||||
}
|
||||
for (const auto& image : stage.images) {
|
||||
bindings.push_back({
|
||||
.binding = binding++,
|
||||
.descriptorType = vk::DescriptorType::eSampledImage,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
|
||||
});
|
||||
}
|
||||
for (const auto& sampler : stage.samplers) {
|
||||
bindings.push_back({
|
||||
.binding = binding++,
|
||||
.descriptorType = vk::DescriptorType::eSampler,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
|
||||
});
|
||||
@@ -217,12 +246,24 @@ vk::UniqueDescriptorSetLayout GraphicsPipeline::BuildSetLayout() const {
|
||||
.bindingCount = static_cast<u32>(bindings.size()),
|
||||
.pBindings = bindings.data(),
|
||||
};
|
||||
return instance.GetDevice().createDescriptorSetLayoutUnique(desc_layout_ci);
|
||||
desc_layout = instance.GetDevice().createDescriptorSetLayoutUnique(desc_layout_ci);
|
||||
}
|
||||
|
||||
void GraphicsPipeline::BindResources(Core::MemoryManager* memory) const {
|
||||
void GraphicsPipeline::BindResources(Core::MemoryManager* memory, StreamBuffer& staging,
|
||||
VideoCore::TextureCache& texture_cache) const {
|
||||
static constexpr u64 MinUniformAlignment = 64;
|
||||
|
||||
const auto map_staging = [&](auto src, size_t size) {
|
||||
const auto [data, offset, _] = staging.Map(size, MinUniformAlignment);
|
||||
std::memcpy(data, reinterpret_cast<const void*>(src), size);
|
||||
staging.Commit(size);
|
||||
return offset;
|
||||
};
|
||||
|
||||
std::array<vk::Buffer, MaxVertexBufferCount> buffers;
|
||||
std::array<vk::DeviceSize, MaxVertexBufferCount> offsets;
|
||||
VAddr base_address = 0;
|
||||
u32 start_offset = 0;
|
||||
|
||||
// Bind vertex buffer.
|
||||
const auto& vs_info = stages[0];
|
||||
@@ -230,38 +271,77 @@ void GraphicsPipeline::BindResources(Core::MemoryManager* memory) const {
|
||||
for (u32 i = 0; i < num_buffers; ++i) {
|
||||
const auto& input = vs_info.vs_inputs[i];
|
||||
const auto buffer = vs_info.ReadUd<AmdGpu::Buffer>(input.sgpr_base, input.dword_offset);
|
||||
std::tie(buffers[i], offsets[i]) = memory->GetVulkanBuffer(buffer.base_address);
|
||||
if (i == 0) {
|
||||
start_offset =
|
||||
map_staging(buffer.base_address.Value(), buffer.stride * buffer.num_records);
|
||||
base_address = buffer.base_address;
|
||||
}
|
||||
buffers[i] = staging.Handle();
|
||||
offsets[i] = start_offset + buffer.base_address - base_address;
|
||||
}
|
||||
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
cmdbuf.bindVertexBuffers(0, num_buffers, buffers.data(), offsets.data());
|
||||
if (num_buffers > 0) {
|
||||
cmdbuf.bindVertexBuffers(0, num_buffers, buffers.data(), offsets.data());
|
||||
}
|
||||
|
||||
// Bind resource buffers and textures.
|
||||
boost::container::static_vector<vk::DescriptorBufferInfo, 4> buffer_infos;
|
||||
boost::container::static_vector<vk::DescriptorImageInfo, 8> image_infos;
|
||||
boost::container::small_vector<vk::WriteDescriptorSet, 16> set_writes;
|
||||
u32 binding{};
|
||||
|
||||
for (const auto& stage : stages) {
|
||||
for (const auto& buffer : stage.buffers) {
|
||||
const auto vsharp = stage.ReadUd<AmdGpu::Buffer>(buffer.sgpr_base, buffer.dword_offset);
|
||||
const auto [vk_buffer, offset] = memory->GetVulkanBuffer(vsharp.base_address);
|
||||
buffer_infos.push_back({
|
||||
.buffer = vk_buffer,
|
||||
.offset = offset,
|
||||
.range = vsharp.stride * vsharp.num_records,
|
||||
});
|
||||
const u32 size = vsharp.stride * vsharp.num_records;
|
||||
const u32 offset = map_staging(vsharp.base_address.Value(), size);
|
||||
buffer_infos.emplace_back(staging.Handle(), offset, size);
|
||||
set_writes.push_back({
|
||||
.dstSet = VK_NULL_HANDLE,
|
||||
.dstBinding = binding,
|
||||
.dstBinding = binding++,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||
.descriptorType = buffer.is_storage ? vk::DescriptorType::eStorageBuffer
|
||||
: vk::DescriptorType::eUniformBuffer,
|
||||
.pBufferInfo = &buffer_infos.back(),
|
||||
});
|
||||
}
|
||||
|
||||
for (const auto& image : stage.images) {
|
||||
const auto tsharp = stage.ReadUd<AmdGpu::Image>(image.sgpr_base, image.dword_offset);
|
||||
const auto& image_view = texture_cache.FindImageView(tsharp);
|
||||
image_infos.emplace_back(VK_NULL_HANDLE, *image_view.image_view,
|
||||
vk::ImageLayout::eGeneral);
|
||||
set_writes.push_back({
|
||||
.dstSet = VK_NULL_HANDLE,
|
||||
.dstBinding = binding++,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = vk::DescriptorType::eSampledImage,
|
||||
.pImageInfo = &image_infos.back(),
|
||||
});
|
||||
}
|
||||
for (const auto& sampler : stage.samplers) {
|
||||
const auto ssharp =
|
||||
stage.ReadUd<AmdGpu::Sampler>(sampler.sgpr_base, sampler.dword_offset);
|
||||
const auto vk_sampler = texture_cache.GetSampler(ssharp);
|
||||
image_infos.emplace_back(vk_sampler, VK_NULL_HANDLE, vk::ImageLayout::eGeneral);
|
||||
set_writes.push_back({
|
||||
.dstSet = VK_NULL_HANDLE,
|
||||
.dstBinding = binding++,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = vk::DescriptorType::eSampler,
|
||||
.pImageInfo = &image_infos.back(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
cmdbuf.pushDescriptorSetKHR(vk::PipelineBindPoint::eGraphics, *pipeline_layout, 0, set_writes);
|
||||
if (!set_writes.empty()) {
|
||||
cmdbuf.pushDescriptorSetKHR(vk::PipelineBindPoint::eGraphics, *pipeline_layout, 0,
|
||||
set_writes);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
@@ -11,6 +11,10 @@ namespace Core {
|
||||
class MemoryManager;
|
||||
}
|
||||
|
||||
namespace VideoCore {
|
||||
class TextureCache;
|
||||
}
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
static constexpr u32 MaxVertexBufferCount = 32;
|
||||
@@ -18,6 +22,7 @@ static constexpr u32 MaxShaderStages = 5;
|
||||
|
||||
class Instance;
|
||||
class Scheduler;
|
||||
class StreamBuffer;
|
||||
|
||||
using Liverpool = AmdGpu::Liverpool;
|
||||
|
||||
@@ -33,6 +38,7 @@ struct PipelineKey {
|
||||
Liverpool::PrimitiveType prim_type;
|
||||
Liverpool::PolygonMode polygon_mode;
|
||||
Liverpool::CullMode cull_mode;
|
||||
std::array<Liverpool::BlendControl, Liverpool::NumColorBuffers> blend_controls;
|
||||
|
||||
bool operator==(const PipelineKey& key) const noexcept {
|
||||
return std::memcmp(this, &key, sizeof(PipelineKey)) == 0;
|
||||
@@ -48,14 +54,15 @@ public:
|
||||
std::array<vk::ShaderModule, MaxShaderStages> modules);
|
||||
~GraphicsPipeline();
|
||||
|
||||
void BindResources(Core::MemoryManager* memory) const;
|
||||
void BindResources(Core::MemoryManager* memory, StreamBuffer& staging,
|
||||
VideoCore::TextureCache& texture_cache) const;
|
||||
|
||||
[[nodiscard]] vk::Pipeline Handle() const noexcept {
|
||||
return *pipeline;
|
||||
}
|
||||
|
||||
private:
|
||||
vk::UniqueDescriptorSetLayout BuildSetLayout() const;
|
||||
void BuildDescSetLayout();
|
||||
|
||||
private:
|
||||
const Instance& instance;
|
||||
|
||||
@@ -151,6 +151,7 @@ bool Instance::CreateDevice() {
|
||||
custom_border_color = add_extension(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
|
||||
index_type_uint8 = add_extension(VK_KHR_INDEX_TYPE_UINT8_EXTENSION_NAME);
|
||||
add_extension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
||||
add_extension(VK_KHR_MAINTENANCE_4_EXTENSION_NAME);
|
||||
|
||||
const auto family_properties = physical_device.getQueueFamilyProperties();
|
||||
if (family_properties.empty()) {
|
||||
@@ -213,6 +214,9 @@ bool Instance::CreateDevice() {
|
||||
vk::PhysicalDeviceIndexTypeUint8FeaturesEXT{
|
||||
.indexTypeUint8 = true,
|
||||
},
|
||||
vk::PhysicalDeviceMaintenance4Features{
|
||||
.maintenance4 = true,
|
||||
},
|
||||
};
|
||||
|
||||
if (!index_type_uint8) {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <fstream>
|
||||
#include <xxhash.h>
|
||||
#include "common/config.h"
|
||||
#include "common/io_file.h"
|
||||
#include "common/path_util.h"
|
||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||
#include "shader_recompiler/recompiler.h"
|
||||
#include "shader_recompiler/runtime_info.h"
|
||||
#include "video_core/amdgpu/resource.h"
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
|
||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||
@@ -41,6 +43,9 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_,
|
||||
: instance{instance_}, scheduler{scheduler_}, liverpool{liverpool_}, inst_pool{8192},
|
||||
block_pool{512} {
|
||||
pipeline_cache = instance.GetDevice().createPipelineCacheUnique({});
|
||||
profile = Shader::Profile{
|
||||
.supported_spirv = 0x00010600U,
|
||||
};
|
||||
}
|
||||
|
||||
const GraphicsPipeline* PipelineCache::GetPipeline() {
|
||||
@@ -63,6 +68,7 @@ void PipelineCache::RefreshKey() {
|
||||
key.stencil_ref_back = regs.stencil_ref_back;
|
||||
key.prim_type = regs.primitive_type;
|
||||
key.polygon_mode = regs.polygon_control.PolyMode();
|
||||
key.blend_controls = regs.blend_control;
|
||||
|
||||
const auto& db = regs.depth_buffer;
|
||||
key.depth_format = key.depth.depth_enable
|
||||
@@ -81,17 +87,15 @@ void PipelineCache::RefreshKey() {
|
||||
key.stage_hashes[i] = 0;
|
||||
continue;
|
||||
}
|
||||
const u32* code = pgm->Address<u32>();
|
||||
|
||||
Shader::BinaryInfo bininfo;
|
||||
std::memcpy(&bininfo, code + (code[1] + 1) * 2, sizeof(bininfo));
|
||||
key.stage_hashes[i] = bininfo.shader_hash;
|
||||
const auto code = pgm->Code();
|
||||
key.stage_hashes[i] = XXH3_64bits(code.data(), code.size_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<GraphicsPipeline> PipelineCache::CreatePipeline() {
|
||||
const auto& regs = liverpool->regs;
|
||||
|
||||
u32 binding{};
|
||||
std::array<Shader::IR::Program, MaxShaderStages> programs;
|
||||
std::array<const Shader::Info*, MaxShaderStages> infos{};
|
||||
|
||||
@@ -101,40 +105,49 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreatePipeline() {
|
||||
continue;
|
||||
}
|
||||
auto* pgm = regs.ProgramForStage(i);
|
||||
const u32* code = pgm->Address<u32>();
|
||||
const auto code = pgm->Code();
|
||||
|
||||
Shader::BinaryInfo bininfo;
|
||||
std::memcpy(&bininfo, code + (code[1] + 1) * 2, sizeof(bininfo));
|
||||
const u32 num_dwords = bininfo.length / sizeof(u32);
|
||||
|
||||
const auto it = module_map.find(bininfo.shader_hash);
|
||||
const auto it = module_map.find(graphics_key.stage_hashes[i]);
|
||||
if (it != module_map.end()) {
|
||||
stages[i] = *it->second;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Dump shader code if requested.
|
||||
const auto stage = Shader::Stage{i};
|
||||
const u64 hash = graphics_key.stage_hashes[i];
|
||||
if (Config::dumpShaders()) {
|
||||
DumpShader(code, hash, stage, "bin");
|
||||
}
|
||||
|
||||
block_pool.ReleaseContents();
|
||||
inst_pool.ReleaseContents();
|
||||
|
||||
// Recompile shader to IR.
|
||||
const auto stage = Shader::Stage{i};
|
||||
const Shader::Info info = MakeShaderInfo(stage, pgm->user_data, regs);
|
||||
programs[i] = Shader::TranslateProgram(inst_pool, block_pool, std::span{code, num_dwords},
|
||||
std::move(info));
|
||||
programs[i] = Shader::TranslateProgram(inst_pool, block_pool, code, std::move(info));
|
||||
|
||||
// Compile IR to SPIR-V
|
||||
const auto profile = Shader::Profile{.supported_spirv = 0x00010600U};
|
||||
const auto spv_code = Shader::Backend::SPIRV::EmitSPIRV(profile, programs[i]);
|
||||
std::ofstream file("shader0.spv", std::ios::out | std::ios::binary);
|
||||
file.write((const char*)spv_code.data(), spv_code.size() * 4);
|
||||
file.close();
|
||||
|
||||
const auto spv_code = Shader::Backend::SPIRV::EmitSPIRV(profile, programs[i], binding);
|
||||
stages[i] = CompileSPV(spv_code, instance.GetDevice());
|
||||
infos[i] = &programs[i].info;
|
||||
|
||||
if (Config::dumpShaders()) {
|
||||
DumpShader(spv_code, hash, stage, "spv");
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_unique<GraphicsPipeline>(instance, scheduler, graphics_key, *pipeline_cache,
|
||||
infos, stages);
|
||||
}
|
||||
|
||||
void PipelineCache::DumpShader(std::span<const u32> code, u64 hash, Shader::Stage stage,
|
||||
std::string_view ext) {
|
||||
using namespace Common::FS;
|
||||
const auto dump_dir = GetUserPath(PathType::ShaderDir) / "dumps";
|
||||
const auto filename = fmt::format("{}_{:#X}.{}", stage, hash, ext);
|
||||
const auto file = IOFile{dump_dir / filename, FileAccessMode::Write};
|
||||
file.WriteSpan(code);
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <tsl/robin_map.h>
|
||||
#include "shader_recompiler/ir/basic_block.h"
|
||||
#include "shader_recompiler/object_pool.h"
|
||||
#include "shader_recompiler/profile.h"
|
||||
#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
|
||||
|
||||
namespace Shader {
|
||||
@@ -32,6 +33,8 @@ private:
|
||||
|
||||
std::unique_ptr<GraphicsPipeline> CreatePipeline();
|
||||
|
||||
void DumpShader(std::span<const u32> code, u64 hash, Shader::Stage stage, std::string_view ext);
|
||||
|
||||
private:
|
||||
const Instance& instance;
|
||||
Scheduler& scheduler;
|
||||
@@ -41,6 +44,7 @@ private:
|
||||
tsl::robin_map<size_t, vk::UniqueShaderModule> module_map;
|
||||
std::array<vk::ShaderModule, MaxShaderStages> stages{};
|
||||
tsl::robin_map<PipelineKey, std::unique_ptr<GraphicsPipeline>> graphics_pipelines;
|
||||
Shader::Profile profile{};
|
||||
PipelineKey graphics_key{};
|
||||
Shader::ObjectPool<Shader::IR::Inst> inst_pool;
|
||||
Shader::ObjectPool<Shader::IR::Block> block_pool;
|
||||
|
||||
@@ -12,16 +12,17 @@
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
static constexpr vk::BufferUsageFlags VertexIndexFlags = vk::BufferUsageFlagBits::eVertexBuffer |
|
||||
vk::BufferUsageFlagBits::eIndexBuffer |
|
||||
vk::BufferUsageFlagBits::eTransferDst;
|
||||
static constexpr vk::BufferUsageFlags VertexIndexFlags =
|
||||
vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndexBuffer |
|
||||
vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eUniformBuffer |
|
||||
vk::BufferUsageFlagBits::eStorageBuffer;
|
||||
|
||||
Rasterizer::Rasterizer(const Instance& instance_, Scheduler& scheduler_,
|
||||
VideoCore::TextureCache& texture_cache_, AmdGpu::Liverpool* liverpool_)
|
||||
: instance{instance_}, scheduler{scheduler_}, texture_cache{texture_cache_},
|
||||
liverpool{liverpool_}, memory{Core::Memory::Instance()},
|
||||
pipeline_cache{instance, scheduler, liverpool},
|
||||
vertex_index_buffer{instance, scheduler, VertexIndexFlags, 64_MB} {
|
||||
vertex_index_buffer{instance, scheduler, VertexIndexFlags, 128_MB} {
|
||||
if (!Config::nullGpu()) {
|
||||
liverpool->BindRasterizer(this);
|
||||
}
|
||||
@@ -35,9 +36,10 @@ void Rasterizer::Draw(bool is_indexed) {
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
const auto& regs = liverpool->regs;
|
||||
const u32 num_indices = SetupIndexBuffer(is_indexed);
|
||||
const auto& image_view = texture_cache.RenderTarget(regs.color_buffers[0]);
|
||||
const GraphicsPipeline* pipeline = pipeline_cache.GetPipeline();
|
||||
pipeline->BindResources(memory);
|
||||
pipeline->BindResources(memory, vertex_index_buffer, texture_cache);
|
||||
|
||||
const auto& image_view = texture_cache.RenderTarget(regs.color_buffers[0]);
|
||||
|
||||
const vk::RenderingAttachmentInfo color_info = {
|
||||
.imageView = *image_view.image_view,
|
||||
@@ -88,18 +90,30 @@ u32 Rasterizer::SetupIndexBuffer(bool& is_indexed) {
|
||||
return regs.num_indices;
|
||||
}
|
||||
|
||||
const VAddr index_address = regs.index_base_address.Address();
|
||||
const auto [buffer, offset] = memory->GetVulkanBuffer(index_address);
|
||||
const vk::IndexType index_type =
|
||||
regs.index_buffer_type.index_type == Liverpool::IndexType::Index16 ? vk::IndexType::eUint16
|
||||
: vk::IndexType::eUint32;
|
||||
// Figure out index type and size.
|
||||
const bool is_index16 = regs.index_buffer_type.index_type == Liverpool::IndexType::Index16;
|
||||
const vk::IndexType index_type = is_index16 ? vk::IndexType::eUint16 : vk::IndexType::eUint32;
|
||||
const u32 index_size = is_index16 ? sizeof(u16) : sizeof(u32);
|
||||
|
||||
// Upload index data to stream buffer.
|
||||
const auto index_address = regs.index_base_address.Address<const void*>();
|
||||
const u32 index_buffer_size = regs.num_indices * 4;
|
||||
const auto [data, offset, _] = vertex_index_buffer.Map(index_buffer_size);
|
||||
std::memcpy(data, index_address, index_buffer_size);
|
||||
vertex_index_buffer.Commit(index_buffer_size);
|
||||
|
||||
// Bind index buffer.
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
cmdbuf.bindIndexBuffer(buffer, offset, index_type);
|
||||
cmdbuf.bindIndexBuffer(vertex_index_buffer.Handle(), offset, index_type);
|
||||
return regs.num_indices;
|
||||
}
|
||||
|
||||
void Rasterizer::UpdateDynamicState() {
|
||||
UpdateViewportScissorState();
|
||||
|
||||
auto& regs = liverpool->regs;
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
cmdbuf.setBlendConstants(®s.blend_constants.red);
|
||||
}
|
||||
|
||||
void Rasterizer::UpdateViewportScissorState() {
|
||||
|
||||
Reference in New Issue
Block a user