-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
VulkanFramebuffer.h
161 lines (124 loc) · 4.84 KB
/
VulkanFramebuffer.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#pragma once
#include "Common/Common.h"
#include "Common/GPU/Vulkan/VulkanContext.h"
class VKRRenderPass;
// Pipelines need to be created for the right type of render pass.
// TODO: Rename to RenderPassFlags?
// When you add more flags, don't forget to update rpTypeDebugNames[].
enum class RenderPassType {
DEFAULT = 0,
// These eight are organized so that bit 0 is DEPTH and bit 1 is INPUT and bit 2 is MULTIVIEW, so
// they can be OR-ed together in MergeRPTypes.
HAS_DEPTH = 1,
MULTIVIEW = 2,
MULTISAMPLE = 4,
// This is the odd one out, and gets special handling in MergeRPTypes.
// If this flag is set, none of the other flags can be set.
// For the backbuffer we can always use CLEAR/DONT_CARE, so bandwidth cost for a depth channel is negligible
// so we don't bother with a non-depth version.
BACKBUFFER = 8,
TYPE_COUNT = BACKBUFFER + 1,
};
ENUM_CLASS_BITOPS(RenderPassType);
// Simple independent framebuffer image.
struct VKRImage {
// These four are "immutable".
VkImage image;
VkImageView rtView; // Used for rendering to, and readbacks of stencil. 2D if single layer, 2D_ARRAY if multiple. Includes both depth and stencil if depth/stencil.
// This is for texturing all layers at once. If aspect is depth/stencil, does not include stencil.
VkImageView texAllLayersView;
// If it's a layered image (for stereo), this is two 2D views of it, to make it compatible with shaders that don't yet support stereo.
// If there's only one layer, layerViews[0] only is initialized.
VkImageView texLayerViews[2]{};
VmaAllocation alloc;
VkFormat format;
VkSampleCountFlagBits sampleCount;
// This one is used by QueueRunner's Perform functions to keep track. CANNOT be used anywhere else due to sync issues.
VkImageLayout layout;
int numLayers;
// For debugging.
std::string tag;
void Delete(VulkanContext *vulkan);
};
class VKRFramebuffer {
public:
VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, int _numLayers, int _multiSampleLevel, bool createDepthStencilBuffer, const char *tag);
~VKRFramebuffer();
VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType);
int width = 0;
int height = 0;
int numLayers = 0;
VkSampleCountFlagBits sampleCount;
VKRImage color{}; // color.image is always there.
VKRImage depth{}; // depth.image is allowed to be VK_NULL_HANDLE.
// These are only initialized and used if numSamples > 1.
VKRImage msaaColor{};
VKRImage msaaDepth{};
const char *Tag() const {
return tag_.c_str();
}
void UpdateTag(const char *newTag);
bool HasDepth() const {
return depth.image != VK_NULL_HANDLE;
}
VkImageView GetRTView() {
if (sampleCount == VK_SAMPLE_COUNT_1_BIT) {
return color.rtView;
} else {
return msaaColor.rtView;
}
}
VulkanContext *Vulkan() const { return vulkan_; }
private:
static void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, int numLayers, VkSampleCountFlagBits sampleCount, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag);
VkFramebuffer framebuf[(size_t)RenderPassType::TYPE_COUNT]{};
VulkanContext *vulkan_;
std::string tag_;
};
inline bool RenderPassTypeHasDepth(RenderPassType type) {
return (type & RenderPassType::HAS_DEPTH) || type == RenderPassType::BACKBUFFER;
}
inline bool RenderPassTypeHasMultiView(RenderPassType type) {
return (type & RenderPassType::MULTIVIEW) != 0;
}
inline bool RenderPassTypeHasMultisample(RenderPassType type) {
return (type & RenderPassType::MULTISAMPLE) != 0;
}
VkSampleCountFlagBits MultiSampleLevelToFlagBits(int count);
// Must be the same order as Draw::RPAction
enum class VKRRenderPassLoadAction : uint8_t {
KEEP, // default. avoid when possible.
CLEAR,
DONT_CARE,
};
enum class VKRRenderPassStoreAction : uint8_t {
STORE, // default. avoid when possible.
DONT_CARE,
};
struct RPKey {
// Only render-pass-compatibility-volatile things can be here.
VKRRenderPassLoadAction colorLoadAction;
VKRRenderPassLoadAction depthLoadAction;
VKRRenderPassLoadAction stencilLoadAction;
VKRRenderPassStoreAction colorStoreAction;
VKRRenderPassStoreAction depthStoreAction;
VKRRenderPassStoreAction stencilStoreAction;
};
class VKRRenderPass {
public:
VKRRenderPass(const RPKey &key) : key_(key) {}
VkRenderPass Get(VulkanContext *vulkan, RenderPassType rpType, VkSampleCountFlagBits sampleCount);
void Destroy(VulkanContext *vulkan) {
for (size_t i = 0; i < (size_t)RenderPassType::TYPE_COUNT; i++) {
if (pass[i]) {
vulkan->Delete().QueueDeleteRenderPass(pass[i]);
}
}
}
private:
// TODO: Might be better off with a hashmap once the render pass type count grows really large..
VkRenderPass pass[(size_t)RenderPassType::TYPE_COUNT]{};
VkSampleCountFlagBits sampleCounts[(size_t)RenderPassType::TYPE_COUNT];
RPKey key_;
};
const char *GetRPTypeName(RenderPassType rpType);