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 "vulkan_common.hpp"
27 #include "memory_allocator.hpp"
28 
29 namespace Vulkan
30 {
31 class Device;
32 
buffer_usage_to_possible_stages(VkBufferUsageFlags usage)33 static inline VkPipelineStageFlags buffer_usage_to_possible_stages(VkBufferUsageFlags usage)
34 {
35 	VkPipelineStageFlags flags = 0;
36 	if (usage & (VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT))
37 		flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
38 	if (usage & (VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT))
39 		flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
40 	if (usage & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT)
41 		flags |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
42 	if (usage & (VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT |
43 	             VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT))
44 		flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
45 		         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
46 	if (usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
47 		flags |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
48 
49 	return flags;
50 }
51 
buffer_usage_to_possible_access(VkBufferUsageFlags usage)52 static inline VkAccessFlags buffer_usage_to_possible_access(VkBufferUsageFlags usage)
53 {
54 	VkAccessFlags flags = 0;
55 	if (usage & (VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT))
56 		flags |= VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
57 	if (usage & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)
58 		flags |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
59 	if (usage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT)
60 		flags |= VK_ACCESS_INDEX_READ_BIT;
61 	if (usage & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT)
62 		flags |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
63 	if (usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)
64 		flags |= VK_ACCESS_UNIFORM_READ_BIT;
65 	if (usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
66 		flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
67 
68 	return flags;
69 }
70 
71 enum class BufferDomain
72 {
73 	Device, // Device local. Probably not visible from CPU.
74 	LinkedDeviceHost, // On desktop, directly mapped VRAM over PCI.
75 	Host, // Host-only, needs to be synced to GPU. Might be device local as well on iGPUs.
76 	CachedHost // Host-only, used for readbacks.
77 };
78 
79 enum BufferMiscFlagBits
80 {
81 	BUFFER_MISC_ZERO_INITIALIZE_BIT = 1 << 0
82 };
83 
84 using BufferMiscFlags = uint32_t;
85 
86 struct BufferCreateInfo
87 {
88 	BufferDomain domain = BufferDomain::Device;
89 	VkDeviceSize size = 0;
90 	VkBufferUsageFlags usage = 0;
91 	BufferMiscFlags misc = 0;
92 };
93 
94 class Buffer;
95 struct BufferDeleter
96 {
97 	void operator()(Buffer *buffer);
98 };
99 
100 class BufferView;
101 struct BufferViewDeleter
102 {
103 	void operator()(BufferView *view);
104 };
105 
106 class Buffer : public Util::IntrusivePtrEnabled<Buffer, BufferDeleter, HandleCounter>,
107                public Cookie, public InternalSyncEnabled
108 {
109 public:
110 	friend struct BufferDeleter;
111 	~Buffer();
112 
get_buffer() const113 	VkBuffer get_buffer() const
114 	{
115 		return buffer;
116 	}
117 
get_create_info() const118 	const BufferCreateInfo &get_create_info() const
119 	{
120 		return info;
121 	}
122 
get_allocation()123 	DeviceAllocation &get_allocation()
124 	{
125 		return alloc;
126 	}
127 
get_allocation() const128 	const DeviceAllocation &get_allocation() const
129 	{
130 		return alloc;
131 	}
132 
133 private:
134 	friend class Util::ObjectPool<Buffer>;
135 	Buffer(Device *device, VkBuffer buffer, const DeviceAllocation &alloc, const BufferCreateInfo &info);
136 
137 	Device *device;
138 	VkBuffer buffer;
139 	DeviceAllocation alloc;
140 	BufferCreateInfo info;
141 };
142 using BufferHandle = Util::IntrusivePtr<Buffer>;
143 
144 struct BufferViewCreateInfo
145 {
146 	const Buffer *buffer;
147 	VkFormat format;
148 	VkDeviceSize offset;
149 	VkDeviceSize range;
150 };
151 
152 class BufferView : public Util::IntrusivePtrEnabled<BufferView, BufferViewDeleter, HandleCounter>,
153                    public Cookie, public InternalSyncEnabled
154 {
155 public:
156 	friend struct BufferViewDeleter;
157 	~BufferView();
158 
get_view() const159 	VkBufferView get_view() const
160 	{
161 		return view;
162 	}
163 
get_create_info()164 	const BufferViewCreateInfo &get_create_info()
165 	{
166 		return info;
167 	}
168 
get_buffer() const169 	const Buffer &get_buffer() const
170 	{
171 		return *info.buffer;
172 	}
173 
174 private:
175 	friend class Util::ObjectPool<BufferView>;
176 	BufferView(Device *device, VkBufferView view, const BufferViewCreateInfo &info);
177 
178 	Device *device;
179 	VkBufferView view;
180 	BufferViewCreateInfo info;
181 };
182 using BufferViewHandle = Util::IntrusivePtr<BufferView>;
183 }
184