VK: Whenever safely possible, shrink the render area.
We just set the render area to the union of the scissor rects used in a pass. Might help some games on some mobile hardware, a little bit. Possibly #13464?
This commit is contained in:
parent
495fd9a13c
commit
332bb7feeb
7 changed files with 115 additions and 14 deletions
|
@ -633,7 +633,9 @@ std::string VulkanQueueRunner::StepToString(const VKRStep &step) const {
|
|||
{
|
||||
int w = step.render.framebuffer ? step.render.framebuffer->width : vulkan_->GetBackbufferWidth();
|
||||
int h = step.render.framebuffer ? step.render.framebuffer->height : vulkan_->GetBackbufferHeight();
|
||||
snprintf(buffer, sizeof(buffer), "RENDER %s (draws: %d, %dx%d, fb: %p, )", step.tag, step.render.numDraws, w, h, step.render.framebuffer);
|
||||
int actual_w = step.render.renderArea.extent.width;
|
||||
int actual_h = step.render.renderArea.extent.height;
|
||||
snprintf(buffer, sizeof(buffer), "RENDER %s (draws: %d, %dx%d/%dx%d, fb: %p, )", step.tag, step.render.numDraws, actual_w, actual_h, w, h, step.render.framebuffer);
|
||||
break;
|
||||
}
|
||||
case VKRStepType::COPY:
|
||||
|
@ -1414,6 +1416,8 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step
|
|||
}
|
||||
} else {
|
||||
framebuf = backbuffer_;
|
||||
|
||||
// Raw, rotated backbuffer size.
|
||||
w = vulkan_->GetBackbufferWidth();
|
||||
h = vulkan_->GetBackbufferHeight();
|
||||
renderPass = GetBackbufferRenderPass();
|
||||
|
@ -1426,10 +1430,20 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step
|
|||
VkRenderPassBeginInfo rp_begin = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
|
||||
rp_begin.renderPass = renderPass;
|
||||
rp_begin.framebuffer = framebuf;
|
||||
rp_begin.renderArea.offset.x = 0;
|
||||
rp_begin.renderArea.offset.y = 0;
|
||||
rp_begin.renderArea.extent.width = w;
|
||||
rp_begin.renderArea.extent.height = h;
|
||||
|
||||
VkRect2D rc = step.render.renderArea;
|
||||
if (!step.render.framebuffer) {
|
||||
// Rendering to backbuffer, must rotate, just like scissors.
|
||||
DisplayRect<int> rotated_rc{ rc.offset.x, rc.offset.y, (int)rc.extent.width, (int)rc.extent.height };
|
||||
RotateRectToDisplay(rotated_rc, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
|
||||
|
||||
rc.offset.x = rotated_rc.x;
|
||||
rc.offset.y = rotated_rc.y;
|
||||
rc.extent.width = rotated_rc.w;
|
||||
rc.extent.height = rotated_rc.h;
|
||||
}
|
||||
|
||||
rp_begin.renderArea = rc;
|
||||
rp_begin.clearValueCount = numClearVals;
|
||||
rp_begin.pClearValues = numClearVals ? clearVal : nullptr;
|
||||
vkCmdBeginRenderPass(cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
|
|
@ -152,6 +152,7 @@ struct VKRStep {
|
|||
VkImageLayout finalColorLayout;
|
||||
VkImageLayout finalDepthStencilLayout;
|
||||
u32 pipelineFlags;
|
||||
VkRect2D renderArea;
|
||||
} render;
|
||||
struct {
|
||||
VKRFramebuffer *src;
|
||||
|
|
|
@ -260,8 +260,8 @@ void VulkanRenderManager::CreateBackbuffers() {
|
|||
if (InitDepthStencilBuffer(cmdInit)) {
|
||||
InitBackbufferFramebuffers(vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
|
||||
}
|
||||
curWidth_ = -1;
|
||||
curHeight_ = -1;
|
||||
curWidthRaw_ = -1;
|
||||
curHeightRaw_ = -1;
|
||||
|
||||
if (HasBackbuffers()) {
|
||||
VLOG("Backbuffers Created");
|
||||
|
@ -529,6 +529,14 @@ void VulkanRenderManager::EndCurRenderStep() {
|
|||
// We'll often be able to avoid loading/saving the depth/stencil buffer.
|
||||
if (curRenderStep_) {
|
||||
curRenderStep_->render.pipelineFlags = curPipelineFlags_;
|
||||
// We don't do this optimization for very small targets, probably not worth it.
|
||||
if (!curRenderArea_.Empty() && (curWidth_ > 32 && curHeight_ > 32)) {
|
||||
curRenderStep_->render.renderArea = curRenderArea_.ToVkRect2D();
|
||||
} else {
|
||||
curRenderStep_->render.renderArea.offset = {};
|
||||
curRenderStep_->render.renderArea.extent = { (uint32_t)curWidth_, (uint32_t)curHeight_ };
|
||||
}
|
||||
curRenderArea_.Reset();
|
||||
|
||||
// We no longer have a current render step.
|
||||
curRenderStep_ = nullptr;
|
||||
|
@ -638,11 +646,20 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR
|
|||
curStepHasViewport_ = false;
|
||||
curStepHasScissor_ = false;
|
||||
if (fb) {
|
||||
curWidthRaw_ = fb->width;
|
||||
curHeightRaw_ = fb->height;
|
||||
curWidth_ = fb->width;
|
||||
curHeight_ = fb->height;
|
||||
} else {
|
||||
curWidth_ = vulkan_->GetBackbufferWidth();
|
||||
curHeight_ = vulkan_->GetBackbufferHeight();
|
||||
curWidthRaw_ = vulkan_->GetBackbufferWidth();
|
||||
curHeightRaw_ = vulkan_->GetBackbufferHeight();
|
||||
if (g_display_rotation == DisplayRotation::ROTATE_90 || g_display_rotation == DisplayRotation::ROTATE_270) {
|
||||
curWidth_ = curHeightRaw_;
|
||||
curHeight_ = curWidthRaw_;
|
||||
} else {
|
||||
curWidth_ = curWidthRaw_;
|
||||
curHeight_ = curHeightRaw_;
|
||||
}
|
||||
}
|
||||
|
||||
// See above - we add a clear afterward if only one side for depth/stencil CLEAR/KEEP.
|
||||
|
@ -944,6 +961,8 @@ void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearSten
|
|||
data.clear.clearMask = clearMask;
|
||||
curRenderStep_->commands.push_back(data);
|
||||
}
|
||||
|
||||
curRenderArea_.SetRect(0, 0, curWidth_, curHeight_);
|
||||
}
|
||||
|
||||
void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, VkImageAspectFlags aspectMask, const char *tag) {
|
||||
|
|
|
@ -61,6 +61,53 @@ enum {
|
|||
MAX_TIMESTAMP_QUERIES = 128,
|
||||
};
|
||||
|
||||
struct BoundingRect {
|
||||
int x1;
|
||||
int y1;
|
||||
int x2;
|
||||
int y2;
|
||||
|
||||
BoundingRect() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
x1 = 65535;
|
||||
y1 = 65535;
|
||||
x2 = -65535;
|
||||
y2 = -65535;
|
||||
}
|
||||
|
||||
bool Empty() const {
|
||||
return x2 < 0;
|
||||
}
|
||||
|
||||
void SetRect(int x, int y, int width, int height) {
|
||||
x1 = x;
|
||||
y1 = y;
|
||||
x2 = width;
|
||||
y2 = height;
|
||||
}
|
||||
|
||||
void Apply(const VkRect2D &rect) {
|
||||
if (rect.offset.x < x1) x1 = rect.offset.x;
|
||||
if (rect.offset.y < y1) y1 = rect.offset.y;
|
||||
int rect_x2 = rect.offset.x + rect.extent.width;
|
||||
int rect_y2 = rect.offset.y + rect.extent.height;
|
||||
if (rect_x2 > x2) x2 = rect_x2;
|
||||
if (rect_y2 > y2) y2 = rect_y2;
|
||||
}
|
||||
|
||||
VkRect2D ToVkRect2D() const {
|
||||
VkRect2D rect;
|
||||
rect.offset.x = x1;
|
||||
rect.offset.y = y1;
|
||||
rect.extent.width = x2 - x1;
|
||||
rect.extent.height = y2 - y1;
|
||||
return rect;
|
||||
}
|
||||
};
|
||||
|
||||
class VulkanRenderManager {
|
||||
public:
|
||||
VulkanRenderManager(VulkanContext *vulkan);
|
||||
|
@ -131,10 +178,22 @@ public:
|
|||
curStepHasViewport_ = true;
|
||||
}
|
||||
|
||||
void SetScissor(const VkRect2D &rc) {
|
||||
void SetScissor(VkRect2D rc) {
|
||||
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
|
||||
_dbg_assert_((int)rc.extent.width >= 0);
|
||||
_dbg_assert_((int)rc.extent.height >= 0);
|
||||
|
||||
// Clamp to curWidth_/curHeight_. Apparently an issue.
|
||||
if ((int)(rc.offset.x + rc.extent.width) > curWidth_) {
|
||||
rc.extent.width = curWidth_ - rc.offset.x;
|
||||
}
|
||||
if ((int)(rc.offset.y + rc.extent.height) > curHeight_) {
|
||||
rc.extent.height = curHeight_ - rc.offset.y;
|
||||
}
|
||||
_dbg_assert_((int)(rc.offset.x + rc.extent.width) <= curWidth_);
|
||||
_dbg_assert_((int)(rc.offset.y + rc.extent.height) <= curHeight_);
|
||||
curRenderArea_.Apply(rc);
|
||||
|
||||
VkRenderData data{ VKRRenderCommand::SCISSOR };
|
||||
data.scissor.scissor = rc;
|
||||
curRenderStep_->commands.push_back(data);
|
||||
|
@ -323,8 +382,15 @@ private:
|
|||
int outOfDateFrames_ = 0;
|
||||
|
||||
// Submission time state
|
||||
|
||||
// Note: These are raw backbuffer-sized. Rotated.
|
||||
int curWidthRaw_ = -1;
|
||||
int curHeightRaw_ = -1;
|
||||
|
||||
// Pre-rotation (as you'd expect).
|
||||
int curWidth_ = -1;
|
||||
int curHeight_ = -1;
|
||||
|
||||
bool insideFrame_ = false;
|
||||
// This is the offset within this frame, in case of a mid-frame sync.
|
||||
int renderStepOffset_ = 0;
|
||||
|
@ -332,6 +398,7 @@ private:
|
|||
bool curStepHasViewport_ = false;
|
||||
bool curStepHasScissor_ = false;
|
||||
u32 curPipelineFlags_ = 0;
|
||||
BoundingRect curRenderArea_;
|
||||
|
||||
std::vector<VKRStep *> steps_;
|
||||
bool splitSubmit_ = false;
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#include "Common/GPU/thin3d.h"
|
||||
#include "Common/UI/Context.h"
|
||||
#include "Common/UI/View.h"
|
||||
#include "Common/System/System.h"
|
||||
#include "Common/System/Display.h"
|
||||
#include "Common/System/System.h"
|
||||
|
||||
#include "DebugVisVulkan.h"
|
||||
#include "Common/GPU/Vulkan/VulkanMemory.h"
|
||||
|
@ -100,7 +100,7 @@ void DrawAllocatorVis(UIContext *ui, GPUInterface *gpu) {
|
|||
iter->Release();
|
||||
}
|
||||
|
||||
void DrawProfilerVis(UIContext *ui, GPUInterface *gpu) {
|
||||
void DrawGPUProfilerVis(UIContext *ui, GPUInterface *gpu) {
|
||||
if (!gpu) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -24,4 +24,4 @@ class UIContext;
|
|||
|
||||
// gpu MUST be an instance of GPU_Vulkan. If not, will definitely crash.
|
||||
void DrawAllocatorVis(UIContext *ui, GPUInterface *gpu);
|
||||
void DrawProfilerVis(UIContext *ui, GPUInterface *gpu);
|
||||
void DrawGPUProfilerVis(UIContext *ui, GPUInterface *gpu);
|
||||
|
|
|
@ -1574,7 +1574,7 @@ void EmuScreen::renderUI() {
|
|||
}
|
||||
|
||||
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN && g_Config.bShowGpuProfile) {
|
||||
DrawProfilerVis(ctx, gpu);
|
||||
DrawGPUProfilerVis(ctx, gpu);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue