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:
parent
612fdb957e
commit
4ef4325fdb
10 changed files with 27 additions and 16 deletions
|
@ -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?
|
||||
}
|
||||
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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...
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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...
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue