GPU: Avoid unnecessary clear on stencil upload.

In this common case, we've typically just bound the buffer to upload a
texture to it.  No need to start a new render pass.

This dodges #12927 but doesn't really fix the underlying issue.
This commit is contained in:
Unknown W. Brackets 2020-05-18 21:30:56 -07:00
parent 612fdb957e
commit 4ef4325fdb
10 changed files with 27 additions and 16 deletions

View file

@ -379,7 +379,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
if (useBufferedRendering_ && !g_Config.bDisableSlowFramebufEffects) {
gpu->PerformMemoryUpload(params.fb_address, byteSize);
NotifyStencilUpload(params.fb_address, byteSize, true);
NotifyStencilUpload(params.fb_address, byteSize, StencilUpload::STENCIL_IS_ZERO);
// TODO: Is it worth trying to upload the depth buffer?
}

View file

@ -146,6 +146,11 @@ inline DrawTextureFlags operator | (const DrawTextureFlags &lhs, const DrawTextu
return DrawTextureFlags((u32)lhs | (u32)rhs);
}
enum class StencilUpload {
NEEDS_CLEAR,
STENCIL_IS_ZERO,
};
enum class TempFBO {
DEPAL,
BLIT,
@ -219,7 +224,7 @@ public:
void NotifyVideoUpload(u32 addr, int size, int width, GEBufferFormat fmt);
void UpdateFromMemory(u32 addr, int size, bool safe);
void ApplyClearToMemory(int x1, int y1, int x2, int y2, u32 clearColor);
virtual bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) = 0;
virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) = 0;
// Returns true if it's sure this is a direct FBO->FBO transfer and it has already handle it.
// In that case we hardly need to actually copy the bytes in VRAM, they will be wrong anyway (unless
// read framebuffers is on, in which case this should always return false).

View file

@ -49,7 +49,7 @@ public:
void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);
virtual bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override;
virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override;
// TODO: Remove
ID3D11Buffer *GetDynamicQuadBuffer() {

View file

@ -70,7 +70,7 @@ VS_OUT main(VS_IN In) {
)";
// TODO : If SV_StencilRef is available (D3D11.3) then this can be done in a single pass.
bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZero) {
bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) {
addr &= 0x3FFFFFFF;
if (!MayIntersectFramebuffer(addr)) {
return false;
@ -117,7 +117,7 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ
}
if (usedBits == 0) {
if (skipZero) {
if (flags == StencilUpload::STENCIL_IS_ZERO) {
// Common when creating buffers, it's already 0. We're done.
return false;
}
@ -164,7 +164,9 @@ bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, bool skipZ
if (!tex)
return false;
if (dstBuffer->fbo) {
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR });
// Typically, STENCIL_IS_ZERO means it's already bound.
Draw::RPAction stencilAction = flags == StencilUpload::STENCIL_IS_ZERO ? Draw::RPAction::KEEP : Draw::RPAction::CLEAR;
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, stencilAction });
} else {
// something is wrong...
}

View file

@ -54,7 +54,7 @@ public:
void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);
virtual bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override;
virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override;
bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes);
bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) override;

View file

@ -66,7 +66,7 @@ VS_OUT main(VS_IN In) {
}
)";
bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, bool skipZero) {
bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) {
addr &= 0x3FFFFFFF;
if (!MayIntersectFramebuffer(addr)) {
return false;
@ -113,7 +113,7 @@ bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, bool skipZer
}
if (usedBits == 0) {
if (skipZero) {
if (flags == StencilUpload::STENCIL_IS_ZERO) {
// Common when creating buffers, it's already 0. We're done.
return false;
}
@ -193,7 +193,9 @@ bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, bool skipZer
u16 h = dstBuffer->renderHeight;
if (dstBuffer->fbo) {
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR });
// Typically, STENCIL_IS_ZERO means it's already bound.
Draw::RPAction stencilAction = flags == StencilUpload::STENCIL_IS_ZERO ? Draw::RPAction::KEEP : Draw::RPAction::CLEAR;
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, stencilAction });
}
D3DVIEWPORT9 vp{ 0, 0, w, h, 0.0f, 1.0f };
device_->SetViewport(&vp);

View file

@ -54,7 +54,7 @@ public:
// For use when texturing from a framebuffer. May create a duplicate if target.
void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);
bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override;
bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override;
bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override;

View file

@ -68,7 +68,7 @@ void main() {
}
)";
bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZero) {
bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) {
addr &= 0x3FFFFFFF;
if (!MayIntersectFramebuffer(addr)) {
return false;
@ -114,7 +114,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe
}
if (usedBits == 0) {
if (skipZero) {
if (flags == StencilUpload::STENCIL_IS_ZERO) {
// Common when creating buffers, it's already 0. We're done.
return false;
}

View file

@ -58,7 +58,7 @@ public:
void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) override;
bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override;
bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override;
VkImageView BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);

View file

@ -96,7 +96,7 @@ void main() {
// In Vulkan we should be able to simply copy the stencil data directly to a stencil buffer without
// messing about with bitplane textures and the like. Or actually, maybe not... Let's start with
// the traditional approach.
bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, bool skipZero) {
bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) {
addr &= 0x3FFFFFFF;
if (!MayIntersectFramebuffer(addr)) {
return false;
@ -168,7 +168,9 @@ bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, bool skip
return false;
if (dstBuffer->fbo) {
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR });
// Typically, STENCIL_IS_ZERO means it's already bound.
Draw::RPAction stencilAction = flags == StencilUpload::STENCIL_IS_ZERO ? Draw::RPAction::KEEP : Draw::RPAction::CLEAR;
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, stencilAction });
} else {
// something is wrong...
}