mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-06-09 12:13:15 +00:00
video_core: Add depth buffer support and fix some bugs (#172)
* memory: Avoid crash when alignment is zero * Also remove unused file * shader_recompiler: Add more instructions * Also fix some minor issues with a few existing instructions * control_flow: Don't emit discard for null exports * renderer_vulkan: Add depth buffer support * liverpool: Fix wrong color buffer number type and viewport zscale * Also add some more formats
This commit is contained in:
parent
e5621759a2
commit
998d046210
26 changed files with 295 additions and 172 deletions
|
@ -176,6 +176,8 @@ vk::BlendOp BlendOp(Liverpool::BlendControl::BlendFunc func) {
|
|||
return vk::BlendOp::eMin;
|
||||
case BlendFunc::Max:
|
||||
return vk::BlendOp::eMax;
|
||||
case BlendFunc::ReverseSubtract:
|
||||
return vk::BlendOp::eReverseSubtract;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -316,7 +318,23 @@ vk::Format SurfaceFormat(AmdGpu::DataFormat data_format, AmdGpu::NumberFormat nu
|
|||
if (data_format == AmdGpu::DataFormat::FormatBc7 && num_format == AmdGpu::NumberFormat::Srgb) {
|
||||
return vk::Format::eBc7SrgbBlock;
|
||||
}
|
||||
UNREACHABLE();
|
||||
if (data_format == AmdGpu::DataFormat::FormatBc1 && num_format == AmdGpu::NumberFormat::Unorm) {
|
||||
return vk::Format::eBc1RgbaUnormBlock;
|
||||
}
|
||||
if (data_format == AmdGpu::DataFormat::FormatBc3 && num_format == AmdGpu::NumberFormat::Unorm) {
|
||||
return vk::Format::eBc3UnormBlock;
|
||||
}
|
||||
if (data_format == AmdGpu::DataFormat::Format8_8_8_8 &&
|
||||
num_format == AmdGpu::NumberFormat::Uint) {
|
||||
return vk::Format::eR8G8B8A8Uint;
|
||||
}
|
||||
if (data_format == AmdGpu::DataFormat::Format16 && num_format == AmdGpu::NumberFormat::Float) {
|
||||
return vk::Format::eR16Sfloat;
|
||||
}
|
||||
if (data_format == AmdGpu::DataFormat::Format32 && num_format == AmdGpu::NumberFormat::Float) {
|
||||
return vk::Format::eR32Sfloat;
|
||||
}
|
||||
UNREACHABLE_MSG("Unknown data_format={} and num_format={}", u32(data_format), u32(num_format));
|
||||
}
|
||||
|
||||
vk::Format DepthFormat(DepthBuffer::ZFormat z_format, DepthBuffer::StencilFormat stencil_format) {
|
||||
|
@ -328,6 +346,14 @@ vk::Format DepthFormat(DepthBuffer::ZFormat z_format, DepthBuffer::StencilFormat
|
|||
stencil_format == DepthBuffer::StencilFormat::Invalid) {
|
||||
return vk::Format::eD32Sfloat;
|
||||
}
|
||||
if (z_format == DepthBuffer::ZFormat::Z16 &&
|
||||
stencil_format == DepthBuffer::StencilFormat::Invalid) {
|
||||
return vk::Format::eD16Unorm;
|
||||
}
|
||||
if (z_format == DepthBuffer::ZFormat::Z16 &&
|
||||
stencil_format == DepthBuffer::StencilFormat::Stencil8) {
|
||||
return vk::Format::eD16UnormS8Uint;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
|
|
@ -64,8 +64,10 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
|||
.pVertexAttributeDescriptions = attributes.data(),
|
||||
};
|
||||
|
||||
ASSERT_MSG(key.prim_type != Liverpool::PrimitiveType::RectList || IsEmbeddedVs(),
|
||||
"Rectangle List primitive type is only supported for embedded VS");
|
||||
if (key.prim_type == Liverpool::PrimitiveType::RectList && !IsEmbeddedVs()) {
|
||||
LOG_WARNING(Render_Vulkan,
|
||||
"Rectangle List primitive type is only supported for embedded VS");
|
||||
}
|
||||
|
||||
const vk::PipelineInputAssemblyStateCreateInfo input_assembly = {
|
||||
.topology = LiverpoolToVK::PrimitiveType(key.prim_type),
|
||||
|
@ -76,11 +78,14 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
|||
.depthClampEnable = false,
|
||||
.rasterizerDiscardEnable = false,
|
||||
.polygonMode = LiverpoolToVK::PolygonMode(key.polygon_mode),
|
||||
.cullMode = vk::CullModeFlagBits::eNone, /*LiverpoolToVK::CullMode(key.cull_mode),*/
|
||||
.cullMode = LiverpoolToVK::CullMode(key.cull_mode),
|
||||
.frontFace = key.front_face == Liverpool::FrontFace::Clockwise
|
||||
? vk::FrontFace::eClockwise
|
||||
: vk::FrontFace::eCounterClockwise,
|
||||
.depthBiasEnable = false,
|
||||
.depthBiasEnable = bool(key.depth_bias_enable),
|
||||
.depthBiasConstantFactor = key.depth_bias_const_factor,
|
||||
.depthBiasClamp = key.depth_bias_clamp,
|
||||
.depthBiasSlopeFactor = key.depth_bias_slope_factor,
|
||||
.lineWidth = 1.0f,
|
||||
};
|
||||
|
||||
|
@ -103,7 +108,12 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
|||
.extent = {1, 1},
|
||||
};
|
||||
|
||||
const vk::PipelineViewportDepthClipControlCreateInfoEXT clip_control = {
|
||||
.negativeOneToOne = key.clip_space == Liverpool::ClipSpace::MinusWToW,
|
||||
};
|
||||
|
||||
const vk::PipelineViewportStateCreateInfo viewport_info = {
|
||||
.pNext = &clip_control,
|
||||
.viewportCount = 1,
|
||||
.pViewports = &viewport,
|
||||
.scissorCount = 1,
|
||||
|
@ -150,6 +160,8 @@ GraphicsPipeline::GraphicsPipeline(const Instance& instance_, Scheduler& schedul
|
|||
.writeMask = key.stencil_ref_back.stencil_write_mask,
|
||||
.reference = key.stencil_ref_back.stencil_test_val,
|
||||
},
|
||||
.minDepthBounds = key.depth_bounds_min,
|
||||
.maxDepthBounds = key.depth_bounds_max,
|
||||
};
|
||||
|
||||
u32 shader_count = 1;
|
||||
|
|
|
@ -32,6 +32,12 @@ struct GraphicsPipelineKey {
|
|||
vk::Format depth_format;
|
||||
|
||||
Liverpool::DepthControl depth;
|
||||
float depth_bounds_min;
|
||||
float depth_bounds_max;
|
||||
float depth_bias_const_factor;
|
||||
float depth_bias_slope_factor;
|
||||
float depth_bias_clamp;
|
||||
u32 depth_bias_enable;
|
||||
Liverpool::StencilControl stencil;
|
||||
Liverpool::StencilRefMask stencil_ref_front;
|
||||
Liverpool::StencilRefMask stencil_ref_back;
|
||||
|
@ -39,7 +45,7 @@ struct GraphicsPipelineKey {
|
|||
Liverpool::PolygonMode polygon_mode;
|
||||
Liverpool::CullMode cull_mode;
|
||||
Liverpool::FrontFace front_face;
|
||||
u32 pad{};
|
||||
Liverpool::ClipSpace clip_space;
|
||||
std::array<Liverpool::BlendControl, Liverpool::NumColorBuffers> blend_controls;
|
||||
std::array<vk::ColorComponentFlags, Liverpool::NumColorBuffers> write_masks;
|
||||
|
||||
|
@ -47,7 +53,6 @@ struct GraphicsPipelineKey {
|
|||
return std::memcmp(this, &key, sizeof(key)) == 0;
|
||||
}
|
||||
};
|
||||
static_assert(std::has_unique_object_representations_v<GraphicsPipelineKey>);
|
||||
|
||||
class GraphicsPipeline {
|
||||
public:
|
||||
|
|
|
@ -155,6 +155,8 @@ bool Instance::CreateDevice() {
|
|||
custom_border_color = add_extension(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
|
||||
add_extension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
||||
add_extension(VK_KHR_MAINTENANCE_4_EXTENSION_NAME);
|
||||
add_extension(VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME);
|
||||
add_extension(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME);
|
||||
// The next two extensions are required to be available together in order to support write masks
|
||||
color_write_en = add_extension(VK_EXT_COLOR_WRITE_ENABLE_EXTENSION_NAME);
|
||||
color_write_en &= add_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
|
||||
|
@ -227,6 +229,9 @@ bool Instance::CreateDevice() {
|
|||
vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT{
|
||||
.extendedDynamicState3ColorWriteMask = true,
|
||||
},
|
||||
vk::PhysicalDeviceDepthClipControlFeaturesEXT{
|
||||
.depthClipControl = true,
|
||||
},
|
||||
};
|
||||
|
||||
if (!color_write_en) {
|
||||
|
|
|
@ -88,12 +88,26 @@ void PipelineCache::RefreshGraphicsKey() {
|
|||
auto& key = graphics_key;
|
||||
|
||||
key.depth = regs.depth_control;
|
||||
key.depth_bounds_min = regs.depth_bounds_min;
|
||||
key.depth_bounds_max = regs.depth_bounds_max;
|
||||
key.depth_bias_enable = regs.polygon_control.enable_polygon_offset_back ||
|
||||
regs.polygon_control.enable_polygon_offset_front ||
|
||||
regs.polygon_control.enable_polygon_offset_para;
|
||||
if (regs.polygon_control.enable_polygon_offset_front) {
|
||||
key.depth_bias_const_factor = regs.poly_offset.front_offset;
|
||||
key.depth_bias_slope_factor = regs.poly_offset.front_scale;
|
||||
} else {
|
||||
key.depth_bias_const_factor = regs.poly_offset.back_offset;
|
||||
key.depth_bias_slope_factor = regs.poly_offset.back_scale;
|
||||
}
|
||||
key.depth_bias_clamp = regs.poly_offset.depth_bias;
|
||||
key.stencil = regs.stencil_control;
|
||||
key.stencil_ref_front = regs.stencil_ref_front;
|
||||
key.stencil_ref_back = regs.stencil_ref_back;
|
||||
key.prim_type = regs.primitive_type;
|
||||
key.polygon_mode = regs.polygon_control.PolyMode();
|
||||
key.cull_mode = regs.polygon_control.CullingMode();
|
||||
key.clip_space = regs.clipper_control.clip_space;
|
||||
key.front_face = regs.polygon_control.front_face;
|
||||
|
||||
const auto& db = regs.depth_buffer;
|
||||
|
@ -103,6 +117,9 @@ void PipelineCache::RefreshGraphicsKey() {
|
|||
// `RenderingInfo` is assumed to be initialized with a contiguous array of valid color
|
||||
// attachments. This might be not a case as HW color buffers can be bound in an arbitrary order.
|
||||
// We need to do some arrays compaction at this stage
|
||||
key.color_formats.fill(vk::Format::eUndefined);
|
||||
key.blend_controls.fill({});
|
||||
key.write_masks.fill({});
|
||||
int remapped_cb{};
|
||||
for (auto cb = 0u; cb < Liverpool::NumColorBuffers; ++cb) {
|
||||
auto const& col_buf = regs.color_buffers[cb];
|
||||
|
@ -112,6 +129,8 @@ void PipelineCache::RefreshGraphicsKey() {
|
|||
key.color_formats[remapped_cb] =
|
||||
LiverpoolToVK::SurfaceFormat(col_buf.info.format, col_buf.NumFormat());
|
||||
key.blend_controls[remapped_cb] = regs.blend_control[cb];
|
||||
key.blend_controls[remapped_cb].enable.Assign(key.blend_controls[remapped_cb].enable &&
|
||||
!col_buf.info.blend_bypass);
|
||||
key.write_masks[remapped_cb] = vk::ColorComponentFlags{regs.color_target_mask.GetMask(cb)};
|
||||
|
||||
++remapped_cb;
|
||||
|
|
|
@ -41,6 +41,8 @@ void Rasterizer::Draw(bool is_indexed, u32 index_offset) {
|
|||
|
||||
boost::container::static_vector<vk::RenderingAttachmentInfo, Liverpool::NumColorBuffers>
|
||||
color_attachments{};
|
||||
vk::RenderingAttachmentInfo depth_attachment{};
|
||||
u32 num_depth_attachments{};
|
||||
for (auto col_buf_id = 0u; col_buf_id < Liverpool::NumColorBuffers; ++col_buf_id) {
|
||||
const auto& col_buf = regs.color_buffers[col_buf_id];
|
||||
if (!col_buf) {
|
||||
|
@ -57,6 +59,17 @@ void Rasterizer::Draw(bool is_indexed, u32 index_offset) {
|
|||
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||
});
|
||||
}
|
||||
if (regs.depth_control.depth_enable && regs.depth_buffer.Address() != 0) {
|
||||
const auto& image_view =
|
||||
texture_cache.DepthTarget(regs.depth_buffer, liverpool->last_db_extent);
|
||||
depth_attachment = {
|
||||
.imageView = *image_view.image_view,
|
||||
.imageLayout = vk::ImageLayout::eGeneral,
|
||||
.loadOp = vk::AttachmentLoadOp::eLoad,
|
||||
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||
};
|
||||
num_depth_attachments++;
|
||||
}
|
||||
|
||||
// TODO: Don't restart renderpass every draw
|
||||
const auto& scissor = regs.screen_scissor;
|
||||
|
@ -69,6 +82,7 @@ void Rasterizer::Draw(bool is_indexed, u32 index_offset) {
|
|||
.layerCount = 1,
|
||||
.colorAttachmentCount = static_cast<u32>(color_attachments.size()),
|
||||
.pColorAttachments = color_attachments.data(),
|
||||
.pDepthAttachment = num_depth_attachments ? &depth_attachment : nullptr,
|
||||
};
|
||||
|
||||
UpdateDynamicState(*pipeline);
|
||||
|
@ -78,7 +92,9 @@ void Rasterizer::Draw(bool is_indexed, u32 index_offset) {
|
|||
if (is_indexed) {
|
||||
cmdbuf.drawIndexed(num_indices, regs.num_instances.NumInstances(), 0, 0, 0);
|
||||
} else {
|
||||
const u32 num_vertices = pipeline->IsEmbeddedVs() ? 4 : regs.num_indices;
|
||||
const u32 num_vertices = regs.primitive_type == AmdGpu::Liverpool::PrimitiveType::RectList
|
||||
? 4
|
||||
: regs.num_indices;
|
||||
cmdbuf.draw(num_vertices, regs.num_instances.NumInstances(), 0, 0);
|
||||
}
|
||||
cmdbuf.endRendering();
|
||||
|
@ -156,13 +172,15 @@ void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) {
|
|||
void Rasterizer::UpdateViewportScissorState() {
|
||||
auto& regs = liverpool->regs;
|
||||
|
||||
const float reduce_z =
|
||||
regs.clipper_control.clip_space == AmdGpu::Liverpool::ClipSpace::MinusWToW ? 1.0f : 0.0f;
|
||||
const auto cmdbuf = scheduler.CommandBuffer();
|
||||
const vk::Viewport viewport{
|
||||
.x = regs.viewports[0].xoffset - regs.viewports[0].xscale,
|
||||
.y = regs.viewports[0].yoffset - regs.viewports[0].yscale,
|
||||
.width = regs.viewports[0].xscale * 2.0f,
|
||||
.height = regs.viewports[0].yscale * 2.0f,
|
||||
.minDepth = regs.viewports[0].zoffset - regs.viewports[0].zscale,
|
||||
.minDepth = regs.viewports[0].zoffset - regs.viewports[0].zscale * reduce_z,
|
||||
.maxDepth = regs.viewports[0].zscale + regs.viewports[0].zoffset,
|
||||
};
|
||||
const vk::Rect2D scissor{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue