mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #12930 from unknownbrackets/gpu-stencil
GPU: Avoid unnecessary clear on stencil upload
This commit is contained in:
commit
f1b9943947
11 changed files with 43 additions and 19 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);
|
||||
|
@ -205,7 +207,7 @@ bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, bool skipZer
|
|||
if (!tex)
|
||||
return false;
|
||||
|
||||
device_->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_STENCIL, D3DCOLOR_RGBA(0, 0, 0, 0), 0.0f, 0);
|
||||
// TODO: Ideally, we should clear alpha to zero here (but not RGB.)
|
||||
|
||||
dxstate.stencilFunc.set(D3DCMP_ALWAYS, 0xFF, 0xFF);
|
||||
|
||||
|
|
|
@ -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...
|
||||
}
|
||||
|
|
|
@ -861,9 +861,22 @@ void VulkanQueueRunner::LogSteps(const std::vector<VKRStep *> &steps) {
|
|||
}
|
||||
}
|
||||
|
||||
const char *RenderPassActionName(VKRRenderPassAction a) {
|
||||
switch (a) {
|
||||
case VKRRenderPassAction::CLEAR:
|
||||
return "CLEAR";
|
||||
case VKRRenderPassAction::DONT_CARE:
|
||||
return "DONT_CARE";
|
||||
case VKRRenderPassAction::KEEP:
|
||||
return "KEEP";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
void VulkanQueueRunner::LogRenderPass(const VKRStep &pass) {
|
||||
int fb = (int)(intptr_t)(pass.render.framebuffer ? pass.render.framebuffer->framebuf : 0);
|
||||
ILOG("RenderPass Begin(%x)", fb);
|
||||
const auto &r = pass.render;
|
||||
int fb = (int)(intptr_t)(r.framebuffer ? r.framebuffer->framebuf : 0);
|
||||
ILOG("RenderPass Begin(%x, %s, %s, %s)", fb, RenderPassActionName(r.color), RenderPassActionName(r.depth), RenderPassActionName(r.stencil));
|
||||
for (auto &cmd : pass.commands) {
|
||||
switch (cmd.cmd) {
|
||||
case VKRRenderCommand::REMOVED:
|
||||
|
|
Loading…
Add table
Reference in a new issue