Permalink
Browse files

Vulkan: Create renderpass objects on demand. Just a refactoring to pr…

…epare for some later features/optimizations.
  • Loading branch information...
hrydgard committed Dec 30, 2017
1 parent b972624 commit 1e64919392d2e98f4fba0832304fc997b73013c5
@@ -7,7 +7,6 @@
void VulkanQueueRunner::CreateDeviceObjects() {
ILOG("VulkanQueueRunner::CreateDeviceObjects");
InitBackbufferRenderPass();
InitRenderpasses();
#if 0
// Just to check whether it makes sense to split some of these. drawidx is way bigger than the others...
@@ -67,11 +66,12 @@ void VulkanQueueRunner::DestroyDeviceObjects() {
vulkan_->Delete().QueueDeleteBuffer(readbackBuffer_);
readbackBufferSize_ = 0;
for (int i = 0; i < ARRAY_SIZE(renderPasses_); i++) {
assert(renderPasses_[i] != VK_NULL_HANDLE);
vulkan_->Delete().QueueDeleteRenderPass(renderPasses_[i]);
renderPasses_[i] = VK_NULL_HANDLE;
}
renderPasses_.Iterate([&](const RPKey &rpkey, VkRenderPass rp) {
_assert_(rp != VK_NULL_HANDLE);
vulkan_->Delete().QueueDeleteRenderPass(rp);
});
renderPasses_.Clear();
assert(backbufferRenderPass_ != VK_NULL_HANDLE);
vulkan_->Delete().QueueDeleteRenderPass(backbufferRenderPass_);
backbufferRenderPass_ = VK_NULL_HANDLE;
@@ -141,13 +141,30 @@ void VulkanQueueRunner::InitBackbufferRenderPass() {
assert(res == VK_SUCCESS);
}
void VulkanQueueRunner::InitRenderpasses() {
VkRenderPass VulkanQueueRunner::GetRenderPass(VKRRenderPassAction colorAction, VKRRenderPassAction depthAction) {
RPKey key{ colorAction, depthAction };
auto pass = renderPasses_.Get(key);
if (pass) {
return pass;
}
// Create a bunch of render pass objects, for normal rendering with a depth buffer,
// with clearing, without clearing, and dont-care for both depth/stencil and color, so 3*3=9 combos.
VkAttachmentDescription attachments[2] = {};
attachments[0].format = VK_FORMAT_R8G8B8A8_UNORM;
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
switch (colorAction) {
case VKRRenderPassAction::CLEAR:
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
break;
case VKRRenderPassAction::KEEP:
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
break;
case VKRRenderPassAction::DONT_CARE:
default:
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
break;
}
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
@@ -157,9 +174,21 @@ void VulkanQueueRunner::InitRenderpasses() {
attachments[1].format = vulkan_->GetDeviceInfo().preferredDepthStencilFormat;
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
switch (depthAction) {
case VKRRenderPassAction::CLEAR:
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
break;
case VKRRenderPassAction::KEEP:
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
break;
case VKRRenderPassAction::DONT_CARE:
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
break;
}
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
@@ -192,31 +221,10 @@ void VulkanQueueRunner::InitRenderpasses() {
rp.pSubpasses = &subpass;
rp.dependencyCount = 0;
for (int depth = 0; depth < 3; depth++) {
switch ((VKRRenderPassAction)depth) {
case VKRRenderPassAction::CLEAR:
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
break;
case VKRRenderPassAction::KEEP:
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
break;
case VKRRenderPassAction::DONT_CARE:
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
break;
}
for (int color = 0; color < 3; color++) {
switch ((VKRRenderPassAction)color) {
case VKRRenderPassAction::CLEAR: attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; break;
case VKRRenderPassAction::KEEP: attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; break;
case VKRRenderPassAction::DONT_CARE: attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; break;
}
int index = RPIndex((VKRRenderPassAction)color, (VKRRenderPassAction)depth);
vkCreateRenderPass(vulkan_->GetDevice(), &rp, nullptr, &renderPasses_[index]);
}
}
VkResult res = vkCreateRenderPass(vulkan_->GetDevice(), &rp, nullptr, &pass);
_assert_(res == VK_SUCCESS);
renderPasses_.Insert(key, pass);
return pass;
}
void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, const std::vector<VKRStep *> &steps) {
@@ -596,7 +604,7 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step
fb->depth.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
}
renderPass = renderPasses_[RPIndex(step.render.color, step.render.depthStencil)];
renderPass = GetRenderPass(step.render.color, step.render.depthStencil);
if (step.render.color == VKRRenderPassAction::CLEAR) {
Uint8x4ToFloat4(clearVal[0].color.float32, step.render.clearColor);
numClearVals = 1;
@@ -2,6 +2,7 @@
#include <cstdint>
#include "Common/Hashmaps.h"
#include "Common/Vulkan/VulkanContext.h"
#include "math/dataconv.h"
#include "thin3d/DataFormat.h"
@@ -87,7 +88,7 @@ enum class VKRStepType : uint8_t {
READBACK_IMAGE,
};
enum class VKRRenderPassAction {
enum class VKRRenderPassAction : uint8_t {
DONT_CARE,
CLEAR,
KEEP,
@@ -144,7 +145,7 @@ struct VKRStep {
class VulkanQueueRunner {
public:
VulkanQueueRunner(VulkanContext *vulkan) : vulkan_(vulkan) {}
VulkanQueueRunner(VulkanContext *vulkan) : vulkan_(vulkan), renderPasses_(16) {}
void SetBackbuffer(VkFramebuffer fb, VkImage img) {
backbuffer_ = fb;
backbufferImage_ = img;
@@ -158,9 +159,7 @@ class VulkanQueueRunner {
VkRenderPass GetBackbufferRenderPass() const {
return backbufferRenderPass_;
}
VkRenderPass GetRenderPass(int i) const {
return renderPasses_[i];
}
VkRenderPass GetRenderPass(VKRRenderPassAction color, VKRRenderPassAction depth);
inline int RPIndex(VKRRenderPassAction color, VKRRenderPassAction depth) {
return (int)depth * 3 + (int)color;
@@ -170,7 +169,6 @@ class VulkanQueueRunner {
private:
void InitBackbufferRenderPass();
void InitRenderpasses();
void PerformBindFramebufferAsRenderTarget(const VKRStep &pass, VkCommandBuffer cmd);
void PerformRenderPass(const VKRStep &pass, VkCommandBuffer cmd);
@@ -197,9 +195,15 @@ class VulkanQueueRunner {
VkFramebuffer curFramebuffer_ = VK_NULL_HANDLE;
VkRenderPass backbufferRenderPass_ = VK_NULL_HANDLE;
struct RPKey {
VKRRenderPassAction colorAction;
VKRRenderPassAction depthStencilAction;
};
// Renderpasses, all combinations of preserving or clearing or dont-care-ing fb contents.
// TODO: Create these on demand.
VkRenderPass renderPasses_[9]{};
DenseHashMap<RPKey, VkRenderPass, (VkRenderPass)VK_NULL_HANDLE> renderPasses_;
// Readback buffer. Currently we only support synchronous readback, so we only really need one.
// We size it generously.
@@ -194,15 +194,15 @@ class VulkanRenderManager {
VkCommandBuffer GetInitCmd();
VkRenderPass GetRenderPass(int pass) const {
return queueRunner_.GetRenderPass(pass);
VkRenderPass GetRenderPass(VKRRenderPassAction color, VKRRenderPassAction depthStencil) {
return queueRunner_.GetRenderPass(color, depthStencil);
}
VkRenderPass GetBackbufferRenderPass() const {
VkRenderPass GetBackbufferRenderPass() {
return queueRunner_.GetBackbufferRenderPass();
}
VkRenderPass GetCompatibleRenderPass() const {
VkRenderPass GetCompatibleRenderPass() {
if (curRenderStep_ && curRenderStep_->render.framebuffer != nullptr) {
return queueRunner_.GetRenderPass(0);
return queueRunner_.GetRenderPass(VKRRenderPassAction::CLEAR, VKRRenderPassAction::CLEAR);
} else {
return queueRunner_.GetBackbufferRenderPass();
}
@@ -462,7 +462,7 @@ class VKContext : public DrawContext {
switch (obj) {
case NativeObject::FRAMEBUFFER_RENDERPASS:
// Return a representative renderpass.
return (uintptr_t)renderManager_.GetRenderPass(0);
return (uintptr_t)renderManager_.GetRenderPass(VKRRenderPassAction::CLEAR, VKRRenderPassAction::CLEAR);
case NativeObject::BACKBUFFER_RENDERPASS:
return (uintptr_t)renderManager_.GetBackbufferRenderPass();
case NativeObject::COMPATIBLE_RENDERPASS:
@@ -1295,7 +1295,7 @@ class VKFramebuffer : public Framebuffer {
Framebuffer *VKContext::CreateFramebuffer(const FramebufferDesc &desc) {
VkCommandBuffer cmd = renderManager_.GetInitCmd();
VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetRenderPass(0), desc.width, desc.height);
VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, cmd, renderManager_.GetRenderPass(VKRRenderPassAction::CLEAR, VKRRenderPassAction::CLEAR), desc.width, desc.height);
return new VKFramebuffer(vkrfb);
}

0 comments on commit 1e64919

Please sign in to comment.