Implement Maxwell3D Depth/Stencil Clears

Support for clearing the depth/stencil RT has been added as its own function via either optimized `VkAttachmentLoadOp`-based clears or `vkCmdClearAttachments`. A bit of cleanup has also been done for color RT clears with the lambda for the slow-path purely calling the command rather than creating the parameter structures.
This commit is contained in:
PixelyIon 2021-12-08 02:25:48 +05:30
parent bf89f96bf5
commit 9e63ecf05d
3 changed files with 101 additions and 39 deletions

View File

@ -404,60 +404,113 @@ namespace skyline::gpu::interconnect {
/* Buffer Clears */ /* Buffer Clears */
private: private:
vk::ClearColorValue clearColorValue{}; //!< The value written to a color buffer being cleared vk::ClearColorValue clearColorValue{}; //!< The value written to the color RT being cleared
vk::ClearDepthStencilValue clearDepthValue{}; //!< The value written to the depth/stencil RT being cleared
public: public:
void UpdateClearColorValue(size_t index, u32 value) { void UpdateClearColorValue(size_t index, u32 value) {
clearColorValue.uint32.at(index) = value; clearColorValue.uint32.at(index) = value;
} }
void ClearBuffers(maxwell3d::ClearBuffers clear) { void UpdateClearDepthValue(float depth) {
auto renderTargetIndex{renderTargetControl[clear.renderTargetId]}; clearDepthValue.depth = depth;
auto renderTarget{GetColorRenderTarget(renderTargetIndex)}; }
if (renderTarget) {
std::lock_guard lock(*renderTarget->texture);
vk::ImageAspectFlags aspect{}; void UpdateClearStencilValue(u32 stencil) {
if (clear.depth) clearDepthValue.stencil = stencil;
aspect |= vk::ImageAspectFlagBits::eDepth; }
if (clear.stencil)
aspect |= vk::ImageAspectFlagBits::eStencil;
if (clear.red || clear.green || clear.blue || clear.alpha)
aspect |= vk::ImageAspectFlagBits::eColor;
aspect &= renderTarget->format->vkAspect;
if (aspect == vk::ImageAspectFlags{}) void ClearColorRt(TextureView *renderTarget, vk::Rect2D scissor, u32 layerIndex) {
return; std::lock_guard lock(*renderTarget);
auto scissor{scissors.at(renderTargetIndex)};
scissor.extent.width = static_cast<u32>(std::min(static_cast<i32>(renderTarget->texture->dimensions.width) - scissor.offset.x, scissor.extent.width = static_cast<u32>(std::min(static_cast<i32>(renderTarget->texture->dimensions.width) - scissor.offset.x,
static_cast<i32>(scissor.extent.width))); static_cast<i32>(scissor.extent.width)));
scissor.extent.height = static_cast<u32>(std::min(static_cast<i32>(renderTarget->texture->dimensions.height) - scissor.offset.y, scissor.extent.height = static_cast<u32>(std::min(static_cast<i32>(renderTarget->texture->dimensions.height) - scissor.offset.y,
static_cast<i32>(scissor.extent.height))); static_cast<i32>(scissor.extent.height)));
if (scissor.extent.width == 0 || scissor.extent.height == 0) if (scissor.extent.width != 0 && scissor.extent.height != 0) {
return; if (scissor.extent.width == renderTarget->texture->dimensions.width && scissor.extent.height == renderTarget->texture->dimensions.height && renderTarget->range.baseArrayLayer == 0 && renderTarget->range.layerCount == 1 && layerIndex == 0) {
if (scissor.extent.width == renderTarget->texture->dimensions.width && scissor.extent.height == renderTarget->texture->dimensions.height && renderTarget->range.baseArrayLayer == 0 && renderTarget->range.layerCount == 1 && clear.layerId == 0) {
executor.AddClearColorSubpass(renderTarget, clearColorValue); executor.AddClearColorSubpass(renderTarget, clearColorValue);
} else { } else {
executor.AddSubpass([aspect, clearColorValue = clearColorValue, layerId = clear.layerId, scissor](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &, GPU &, vk::RenderPass, u32) { vk::ClearAttachment clearAttachment{
commandBuffer.clearAttachments(vk::ClearAttachment{ .aspectMask = vk::ImageAspectFlagBits::eColor,
.aspectMask = aspect,
.colorAttachment = 0, .colorAttachment = 0,
.clearValue = clearColorValue, .clearValue = clearColorValue,
}, vk::ClearRect{ };
vk::ClearRect clearRect{
.rect = scissor, .rect = scissor,
.baseArrayLayer = layerId, .baseArrayLayer = layerIndex,
.layerCount = 1, .layerCount = 1,
}); };
}, vk::Rect2D{
.extent = renderTarget->texture->dimensions, executor.AddSubpass([clearAttachment, clearRect](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &, GPU &, vk::RenderPass, u32) {
}, {}, {renderTarget}); commandBuffer.clearAttachments(clearAttachment, clearRect);
}, vk::Rect2D{.extent = renderTarget->texture->dimensions}, {}, renderTarget);
} }
} }
} }
void ClearDepthStencilRt(TextureView *renderTarget, vk::ImageAspectFlags aspect, u32 layerIndex) {
std::lock_guard lock(*renderTarget);
if (renderTarget->range.layerCount == 1 && layerIndex == 0) {
executor.AddClearDepthStencilSubpass(renderTarget, clearDepthValue);
} else {
vk::ClearAttachment clearAttachment{
.aspectMask = aspect,
.clearValue = clearDepthValue,
};
auto &dimensions{renderTarget->texture->dimensions};
vk::Rect2D imageArea{
.extent = vk::Extent2D{
.width = dimensions.width,
.height = dimensions.height
},
};
vk::ClearRect clearRect{
.rect = imageArea,
.baseArrayLayer = layerIndex,
.layerCount = 1,
};
executor.AddSubpass([clearAttachment, clearRect](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &, GPU &, vk::RenderPass, u32) {
commandBuffer.clearAttachments(clearAttachment, clearRect);
}, imageArea, {}, {}, renderTarget);
}
}
void ClearBuffers(maxwell3d::ClearBuffers clear) {
bool isColor{clear.red || clear.green || clear.blue || clear.alpha};
auto renderTargetIndex{renderTargetControl[clear.renderTargetId]};
auto colorRenderTargetView{isColor ? GetColorRenderTarget(renderTargetIndex) : nullptr};
if (colorRenderTargetView) {
if (!clear.red || !clear.green || !clear.blue || !clear.alpha)
throw exception("Atomically clearing color channels is not supported ({}{}{}{})", clear.red ? 'R' : '-', clear.green ? 'G' : '-', clear.blue ? 'B' : '-', clear.alpha ? 'A' : '-');
if (colorRenderTargetView->format->vkAspect & vk::ImageAspectFlagBits::eColor)
ClearColorRt(colorRenderTargetView, scissors.at(renderTargetIndex), clear.layerId);
}
bool isDepth{clear.depth || clear.stencil};
auto depthRenderTargetView{isDepth ? GetDepthRenderTarget() : nullptr};
if (depthRenderTargetView) {
vk::ImageAspectFlags aspect{};
if (clear.depth)
aspect |= vk::ImageAspectFlagBits::eDepth;
if (clear.stencil)
aspect |= vk::ImageAspectFlagBits::eStencil;
aspect &= depthRenderTargetView->format->vkAspect;
if (aspect)
ClearDepthStencilRt(depthRenderTargetView, aspect, clear.layerId);
}
}
/* Shader Program */ /* Shader Program */
private: private:
struct Shader { struct Shader {

View File

@ -176,6 +176,14 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
static_assert(4 < BOOST_PP_LIMIT_REPEAT); static_assert(4 < BOOST_PP_LIMIT_REPEAT);
#undef COLOR_CLEAR_CALLBACKS #undef COLOR_CLEAR_CALLBACKS
MAXWELL3D_CASE(clearDepthValue, {
context.UpdateClearDepthValue(clearDepthValue);
})
MAXWELL3D_CASE(clearStencilValue, {
context.UpdateClearStencilValue(clearStencilValue);
})
MAXWELL3D_STRUCT_CASE(polygonMode, front, { MAXWELL3D_STRUCT_CASE(polygonMode, front, {
context.SetPolygonModeFront(front); context.SetPolygonModeFront(front);
}) })

View File

@ -76,7 +76,8 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
Register<0x35E, u32> drawVertexCount; //!< The amount of vertices to draw, calling this method triggers drawing Register<0x35E, u32> drawVertexCount; //!< The amount of vertices to draw, calling this method triggers drawing
Register<0x360, std::array<u32, 4>> clearColorValue; Register<0x360, std::array<u32, 4>> clearColorValue;
Register<0x364, u32> clearDepthValue; Register<0x364, float> clearDepthValue;
Register<0x368, u32> clearStencilValue;
struct PolygonMode { struct PolygonMode {
type::PolygonMode front; // 0x36B type::PolygonMode front; // 0x36B