Fix bad framebuffer bind in Parappa The Rapper

This commit is contained in:
Henrik Rydgård 2024-05-29 12:23:54 +02:00
parent e5662f63d5
commit 87ead3f492
4 changed files with 32 additions and 6 deletions

View file

@ -154,9 +154,9 @@ struct VKRStep {
VKRRenderPassStoreAction colorStore; VKRRenderPassStoreAction colorStore;
VKRRenderPassStoreAction depthStore; VKRRenderPassStoreAction depthStore;
VKRRenderPassStoreAction stencilStore; VKRRenderPassStoreAction stencilStore;
u8 clearStencil;
uint32_t clearColor; uint32_t clearColor;
float clearDepth; float clearDepth;
u8 clearStencil;
int numDraws; int numDraws;
// Downloads and textures from this pass. // Downloads and textures from this pass.
int numReads; int numReads;
@ -173,20 +173,20 @@ struct VKRStep {
VKRFramebuffer *dst; VKRFramebuffer *dst;
VkRect2D srcRect; VkRect2D srcRect;
VkOffset2D dstPos; VkOffset2D dstPos;
int aspectMask; VkImageAspectFlags aspectMask;
} copy; } copy;
struct { struct {
VKRFramebuffer *src; VKRFramebuffer *src;
VKRFramebuffer *dst; VKRFramebuffer *dst;
VkRect2D srcRect; VkRect2D srcRect;
VkRect2D dstRect; VkRect2D dstRect;
int aspectMask; VkImageAspectFlags aspectMask;
VkFilter filter; VkFilter filter;
} blit; } blit;
struct { struct {
int aspectMask;
VKRFramebuffer *src; VKRFramebuffer *src;
VkRect2D srcRect; VkRect2D srcRect;
VkImageAspectFlags aspectMask;
bool delayed; bool delayed;
} readback; } readback;
struct { struct {

View file

@ -900,6 +900,11 @@ void VulkanRenderManager::EndCurRenderStep() {
void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth, VKRRenderPassLoadAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag) { void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth, VKRRenderPassLoadAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag) {
_dbg_assert_(insideFrame_); _dbg_assert_(insideFrame_);
#ifdef _DEBUG
SanityCheckPassesOnAdd();
#endif
// Eliminate dupes (bind of the framebuffer we already are rendering to), instantly convert to a clear if possible. // Eliminate dupes (bind of the framebuffer we already are rendering to), instantly convert to a clear if possible.
if (!steps_.empty() && steps_.back()->stepType == VKRStepType::RENDER && steps_.back()->render.framebuffer == fb) { if (!steps_.empty() && steps_.back()->stepType == VKRStepType::RENDER && steps_.back()->render.framebuffer == fb) {
u32 clearMask = 0; u32 clearMask = 0;
@ -1233,6 +1238,10 @@ void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearSten
} }
void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, VkImageAspectFlags aspectMask, const char *tag) { void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, VkImageAspectFlags aspectMask, const char *tag) {
#ifdef _DEBUG
SanityCheckPassesOnAdd();
#endif
_dbg_assert_msg_(srcRect.offset.x >= 0, "srcrect offset x (%d) < 0", srcRect.offset.x); _dbg_assert_msg_(srcRect.offset.x >= 0, "srcrect offset x (%d) < 0", srcRect.offset.x);
_dbg_assert_msg_(srcRect.offset.y >= 0, "srcrect offset y (%d) < 0", srcRect.offset.y); _dbg_assert_msg_(srcRect.offset.y >= 0, "srcrect offset y (%d) < 0", srcRect.offset.y);
_dbg_assert_msg_(srcRect.offset.x + srcRect.extent.width <= (uint32_t)src->width, "srcrect offset x (%d) + extent (%d) > width (%d)", srcRect.offset.x, srcRect.extent.width, (uint32_t)src->width); _dbg_assert_msg_(srcRect.offset.x + srcRect.extent.width <= (uint32_t)src->width, "srcrect offset x (%d) + extent (%d) > width (%d)", srcRect.offset.x, srcRect.extent.width, (uint32_t)src->width);
@ -1297,6 +1306,10 @@ void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect,
} }
void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, VkImageAspectFlags aspectMask, VkFilter filter, const char *tag) { void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, VkImageAspectFlags aspectMask, VkFilter filter, const char *tag) {
#ifdef _DEBUG
SanityCheckPassesOnAdd();
#endif
_dbg_assert_msg_(srcRect.offset.x >= 0, "srcrect offset x (%d) < 0", srcRect.offset.x); _dbg_assert_msg_(srcRect.offset.x >= 0, "srcrect offset x (%d) < 0", srcRect.offset.x);
_dbg_assert_msg_(srcRect.offset.y >= 0, "srcrect offset y (%d) < 0", srcRect.offset.y); _dbg_assert_msg_(srcRect.offset.y >= 0, "srcrect offset y (%d) < 0", srcRect.offset.y);
_dbg_assert_msg_(srcRect.offset.x + srcRect.extent.width <= (uint32_t)src->width, "srcrect offset x (%d) + extent (%d) > width (%d)", srcRect.offset.x, srcRect.extent.width, (uint32_t)src->width); _dbg_assert_msg_(srcRect.offset.x + srcRect.extent.width <= (uint32_t)src->width, "srcrect offset x (%d) + extent (%d) > width (%d)", srcRect.offset.x, srcRect.extent.width, (uint32_t)src->width);
@ -1849,3 +1862,14 @@ void VKRPipelineLayout::FlushDescSets(VulkanContext *vulkan, int frame, QueuePro
profile->descriptorsWritten += writeCount; profile->descriptorsWritten += writeCount;
profile->descriptorsDeduped += dedupCount; profile->descriptorsDeduped += dedupCount;
} }
void VulkanRenderManager::SanityCheckPassesOnAdd() {
#if _DEBUG
// Check that we don't have any previous passes that write to the backbuffer, that must ALWAYS be the last one.
for (int i = 0; i < steps_.size(); i++) {
if (steps_[i]->stepType == VKRStepType::RENDER) {
_dbg_assert_(steps_[i]->render.framebuffer != nullptr);
}
}
#endif
}

View file

@ -554,6 +554,8 @@ private:
void ResetDescriptorLists(int frame); void ResetDescriptorLists(int frame);
void FlushDescriptors(int frame); void FlushDescriptors(int frame);
void SanityCheckPassesOnAdd();
FrameDataShared frameDataShared_; FrameDataShared frameDataShared_;
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES]; FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES];

View file

@ -3272,8 +3272,8 @@ void FramebufferManagerCommon::RebindFramebuffer(const char *tag) {
if (currentRenderVfb_ && currentRenderVfb_->fbo) { if (currentRenderVfb_ && currentRenderVfb_->fbo) {
draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag);
} else { } else {
// Should this even happen? It could while debugging, but maybe we can just skip binding at all. // This can happen (like it does in Parappa) when a frame starts with copies instead of rendering.
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "RebindFramebuffer_Bad"); // Let's do nothing and assume it'll take care of itself.
} }
} }