Skip to content

Commit

Permalink
VK: Whenever safely possible, shrink the render area.
Browse files Browse the repository at this point in the history
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?
  • Loading branch information
hrydgard committed Oct 11, 2020
1 parent 495fd9a commit 332bb7f
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 14 deletions.
24 changes: 19 additions & 5 deletions Common/GPU/Vulkan/VulkanQueueRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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();
Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions Common/GPU/Vulkan/VulkanQueueRunner.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ struct VKRStep {
VkImageLayout finalColorLayout;
VkImageLayout finalDepthStencilLayout;
u32 pipelineFlags;
VkRect2D renderArea;
} render;
struct {
VKRFramebuffer *src;
Expand Down
27 changes: 23 additions & 4 deletions Common/GPU/Vulkan/VulkanRenderManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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) {
Expand Down
69 changes: 68 additions & 1 deletion Common/GPU/Vulkan/VulkanRenderManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -131,10 +178,22 @@ class VulkanRenderManager {
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);
Expand Down Expand Up @@ -323,15 +382,23 @@ class VulkanRenderManager {
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;
VKRStep *curRenderStep_ = nullptr;
bool curStepHasViewport_ = false;
bool curStepHasScissor_ = false;
u32 curPipelineFlags_ = 0;
BoundingRect curRenderArea_;

std::vector<VKRStep *> steps_;
bool splitSubmit_ = false;
Expand Down
4 changes: 2 additions & 2 deletions GPU/Vulkan/DebugVisVulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion GPU/Vulkan/DebugVisVulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
2 changes: 1 addition & 1 deletion UI/EmuScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1574,7 +1574,7 @@ void EmuScreen::renderUI() {
}

if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN && g_Config.bShowGpuProfile) {
DrawProfilerVis(ctx, gpu);
DrawGPUProfilerVis(ctx, gpu);
}

#endif
Expand Down

0 comments on commit 332bb7f

Please sign in to comment.