mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-29 16:55:28 +03:00
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:
parent
bf89f96bf5
commit
9e63ecf05d
@ -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 {
|
||||||
|
@ -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);
|
||||||
})
|
})
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user