1 /* Copyright (c) 2017-2018 Hans-Kristian Arntzen
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be
12  * included in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 #pragma once
24 
25 #include "cookie.hpp"
26 #include "hash.hpp"
27 #include "image.hpp"
28 #include "intrusive.hpp"
29 #include "limits.hpp"
30 #include "object_pool.hpp"
31 #include "temporary_hashmap.hpp"
32 #include "vulkan.hpp"
33 
34 namespace Vulkan
35 {
36 enum RenderPassOp
37 {
38 	RENDER_PASS_OP_CLEAR_DEPTH_STENCIL_BIT = 1 << 0,
39 	RENDER_PASS_OP_LOAD_DEPTH_STENCIL_BIT = 1 << 1,
40 	RENDER_PASS_OP_STORE_DEPTH_STENCIL_BIT = 1 << 2,
41 	RENDER_PASS_OP_DEPTH_STENCIL_READ_ONLY_BIT = 1 << 3,
42 	RENDER_PASS_OP_ENABLE_TRANSIENT_STORE_BIT = 1 << 4,
43 	RENDER_PASS_OP_ENABLE_TRANSIENT_LOAD_BIT = 1 << 5
44 };
45 using RenderPassOpFlags = uint32_t;
46 
47 class ImageView;
48 struct RenderPassInfo
49 {
50 	ImageView *color_attachments[VULKAN_NUM_ATTACHMENTS];
51 	ImageView *depth_stencil = nullptr;
52 	unsigned num_color_attachments = 0;
53 	RenderPassOpFlags op_flags = 0;
54 	uint32_t clear_attachments = 0;
55 	uint32_t load_attachments = 0;
56 	uint32_t store_attachments = 0;
57 	uint32_t layer = 0;
58 
59 	// Render area will be clipped to the actual framebuffer.
60 	VkRect2D render_area = { { 0, 0 }, { UINT32_MAX, UINT32_MAX } };
61 
62 	VkClearColorValue clear_color[VULKAN_NUM_ATTACHMENTS] = {};
63 	VkClearDepthStencilValue clear_depth_stencil = { 1.0f, 0 };
64 
65 	enum class DepthStencil
66 	{
67 		None,
68 		ReadOnly,
69 		ReadWrite
70 	};
71 
72 	struct Subpass
73 	{
74 		uint32_t color_attachments[VULKAN_NUM_ATTACHMENTS];
75 		uint32_t input_attachments[VULKAN_NUM_ATTACHMENTS];
76 		uint32_t resolve_attachments[VULKAN_NUM_ATTACHMENTS];
77 		unsigned num_color_attachments = 0;
78 		unsigned num_input_attachments = 0;
79 		unsigned num_resolve_attachments = 0;
80 		DepthStencil depth_stencil_mode = DepthStencil::ReadWrite;
81 	};
82 	// If 0/nullptr, assume a default subpass.
83 	const Subpass *subpasses = nullptr;
84 	unsigned num_subpasses = 0;
85 };
86 
87 class RenderPass : public HashedObject<RenderPass>, public NoCopyNoMove
88 {
89 public:
90 	struct SubpassInfo
91 	{
92 		VkAttachmentReference color_attachments[VULKAN_NUM_ATTACHMENTS];
93 		unsigned num_color_attachments;
94 		VkAttachmentReference input_attachments[VULKAN_NUM_ATTACHMENTS];
95 		unsigned num_input_attachments;
96 		VkAttachmentReference depth_stencil_attachment;
97 
98 		unsigned samples;
99 	};
100 
101 	RenderPass(Util::Hash hash, Device *device, const RenderPassInfo &info);
102 	RenderPass(Util::Hash hash, Device *device, const VkRenderPassCreateInfo &create_info);
103 	~RenderPass();
104 
get_num_subpasses() const105 	unsigned get_num_subpasses() const
106 	{
107 		return unsigned(subpasses.size());
108 	}
109 
get_render_pass() const110 	VkRenderPass get_render_pass() const
111 	{
112 		return render_pass;
113 	}
114 
get_sample_count(unsigned subpass) const115 	uint32_t get_sample_count(unsigned subpass) const
116 	{
117 		VK_ASSERT(subpass < subpasses.size());
118 		return subpasses[subpass].samples;
119 	}
120 
get_num_color_attachments(unsigned subpass) const121 	unsigned get_num_color_attachments(unsigned subpass) const
122 	{
123 		VK_ASSERT(subpass < subpasses.size());
124 		return subpasses[subpass].num_color_attachments;
125 	}
126 
get_num_input_attachments(unsigned subpass) const127 	unsigned get_num_input_attachments(unsigned subpass) const
128 	{
129 		VK_ASSERT(subpass < subpasses.size());
130 		return subpasses[subpass].num_input_attachments;
131 	}
132 
get_color_attachment(unsigned subpass,unsigned index) const133 	const VkAttachmentReference &get_color_attachment(unsigned subpass, unsigned index) const
134 	{
135 		VK_ASSERT(subpass < subpasses.size());
136 		VK_ASSERT(index < subpasses[subpass].num_color_attachments);
137 		return subpasses[subpass].color_attachments[index];
138 	}
139 
get_input_attachment(unsigned subpass,unsigned index) const140 	const VkAttachmentReference &get_input_attachment(unsigned subpass, unsigned index) const
141 	{
142 		VK_ASSERT(subpass < subpasses.size());
143 		VK_ASSERT(index < subpasses[subpass].num_input_attachments);
144 		return subpasses[subpass].input_attachments[index];
145 	}
146 
has_depth(unsigned subpass) const147 	bool has_depth(unsigned subpass) const
148 	{
149 		VK_ASSERT(subpass < subpasses.size());
150 		return subpasses[subpass].depth_stencil_attachment.attachment != VK_ATTACHMENT_UNUSED &&
151 		       format_has_depth_aspect(depth_stencil);
152 	}
153 
has_stencil(unsigned subpass) const154 	bool has_stencil(unsigned subpass) const
155 	{
156 		VK_ASSERT(subpass < subpasses.size());
157 		return subpasses[subpass].depth_stencil_attachment.attachment != VK_ATTACHMENT_UNUSED &&
158 		       format_has_stencil_aspect(depth_stencil);
159 	}
160 
161 private:
162 	Device *device;
163 	VkRenderPass render_pass = VK_NULL_HANDLE;
164 
165 	VkFormat color_attachments[VULKAN_NUM_ATTACHMENTS] = {};
166 	VkFormat depth_stencil = VK_FORMAT_UNDEFINED;
167 	std::vector<SubpassInfo> subpasses;
168 
169 	void setup_subpasses(const VkRenderPassCreateInfo &create_info);
170 
171 	void fixup_render_pass_nvidia(VkRenderPassCreateInfo &create_info, VkAttachmentDescription *attachments);
172 	void fixup_wsi_barrier(VkRenderPassCreateInfo &create_info, VkAttachmentDescription *attachments);
173 };
174 
175 class Framebuffer : public Cookie, public NoCopyNoMove, public InternalSyncEnabled
176 {
177 public:
178 	Framebuffer(Device *device, const RenderPass &rp, const RenderPassInfo &info);
179 	~Framebuffer();
180 
get_framebuffer() const181 	VkFramebuffer get_framebuffer() const
182 	{
183 		return framebuffer;
184 	}
185 
get_attachment(unsigned index) const186 	ImageView *get_attachment(unsigned index) const
187 	{
188 		assert(index < attachments.size());
189 		return attachments[index];
190 	}
191 
get_width() const192 	uint32_t get_width() const
193 	{
194 		return width;
195 	}
196 
get_height() const197 	uint32_t get_height() const
198 	{
199 		return height;
200 	}
201 
get_compatible_render_pass() const202 	const RenderPass &get_compatible_render_pass() const
203 	{
204 		return render_pass;
205 	}
206 
207 private:
208 	Device *device;
209 	VkFramebuffer framebuffer = VK_NULL_HANDLE;
210 	const RenderPass &render_pass;
211 	RenderPassInfo info;
212 	uint32_t width = 0;
213 	uint32_t height = 0;
214 
215 	std::vector<ImageView *> attachments;
216 };
217 
218 static const unsigned VULKAN_FRAMEBUFFER_RING_SIZE = 8;
219 class FramebufferAllocator
220 {
221 public:
222 	FramebufferAllocator(Device *device);
223 	Framebuffer &request_framebuffer(const RenderPassInfo &info);
224 
225 	void begin_frame();
226 	void clear();
227 
228 private:
229 	struct FramebufferNode : Util::TemporaryHashmapEnabled<FramebufferNode>,
230 	                         Util::IntrusiveListEnabled<FramebufferNode>,
231 	                         Framebuffer
232 	{
FramebufferNodeVulkan::FramebufferAllocator::FramebufferNode233 		FramebufferNode(Device *device, const RenderPass &rp, const RenderPassInfo &info)
234 		    : Framebuffer(device, rp, info)
235 		{
236 			set_internal_sync_object();
237 		}
238 	};
239 
240 	Device *device;
241 	Util::TemporaryHashmap<FramebufferNode, VULKAN_FRAMEBUFFER_RING_SIZE, false> framebuffers;
242 #ifdef GRANITE_VULKAN_MT
243 	std::mutex lock;
244 #endif
245 };
246 
247 class AttachmentAllocator
248 {
249 public:
AttachmentAllocator(Device * device,bool transient)250 	AttachmentAllocator(Device *device, bool transient)
251 		: device(device), transient(transient)
252 	{
253 	}
254 
255 	ImageView &request_attachment(unsigned width, unsigned height, VkFormat format,
256 	                              unsigned index = 0, unsigned samples = 1, unsigned layers = 1);
257 
258 	void begin_frame();
259 	void clear();
260 
261 private:
262 	struct TransientNode : Util::TemporaryHashmapEnabled<TransientNode>, Util::IntrusiveListEnabled<TransientNode>
263 	{
TransientNodeVulkan::AttachmentAllocator::TransientNode264 		TransientNode(ImageHandle handle)
265 		    : handle(handle)
266 		{
267 		}
268 
269 		ImageHandle handle;
270 	};
271 
272 	Device *device;
273 	Util::TemporaryHashmap<TransientNode, VULKAN_FRAMEBUFFER_RING_SIZE, false> attachments;
274 #ifdef GRANITE_VULKAN_MT
275 	std::mutex lock;
276 #endif
277 	bool transient;
278 };
279 
280 class TransientAttachmentAllocator : public AttachmentAllocator
281 {
282 public:
TransientAttachmentAllocator(Device * device)283 	TransientAttachmentAllocator(Device *device)
284 		: AttachmentAllocator(device, true)
285 	{
286 	}
287 };
288 
289 class PhysicalAttachmentAllocator : public AttachmentAllocator
290 {
291 public:
PhysicalAttachmentAllocator(Device * device)292 	PhysicalAttachmentAllocator(Device *device)
293 		: AttachmentAllocator(device, false)
294 	{
295 	}
296 };
297 
298 }
299 
300