Line data Source code
1 : /**
2 : Copyright (c) 2021 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #ifndef XENOLITH_BACKEND_VK_XLVKDEVICEQUEUE_H_
25 : #define XENOLITH_BACKEND_VK_XLVKDEVICEQUEUE_H_
26 :
27 : #include "XLVkInstance.h"
28 : #include "XLVkLoop.h"
29 : #include "XLCoreDevice.h"
30 : #include "XLCoreLoop.h"
31 : #include "XLCoreFrameHandle.h"
32 :
33 : namespace STAPPLER_VERSIONIZED stappler::xenolith::vk {
34 :
35 : class Device;
36 : class DeviceQueue;
37 : class CommandPool;
38 : class Semaphore;
39 : class Fence;
40 : class Loop;
41 : class Image;
42 : class ImageView;
43 : class Buffer;
44 : class RenderPass;
45 : class Framebuffer;
46 : class GraphicPipeline;
47 : class ComputePipeline;
48 : class CommandBuffer;
49 : class DeviceMemoryPool;
50 : struct DescriptorSet;
51 :
52 : using PipelineDescriptor = core::PipelineDescriptor;
53 :
54 : struct DeviceQueueFamily {
55 : using FrameHandle = core::FrameHandle;
56 :
57 : struct Waiter {
58 : Function<void(Loop &, const Rc<DeviceQueue> &)> acquireForLoop;
59 : Function<void(Loop &)> releaseForLoop;
60 : Function<void(FrameHandle &, const Rc<DeviceQueue> &)> acquireForFrame;
61 : Function<void(FrameHandle &)> releaseForFrame;
62 :
63 : Rc<FrameHandle> handle;
64 : Rc<Loop> loop;
65 : Rc<Ref> ref;
66 :
67 1 : Waiter(Function<void(FrameHandle &, const Rc<DeviceQueue> &)> &&a, Function<void(FrameHandle &)> &&r,
68 : FrameHandle *h, Rc<Ref> &&ref)
69 1 : : acquireForFrame(move(a)), releaseForFrame(move(r)), handle(h), ref(move(ref)) { }
70 :
71 0 : Waiter(Function<void(Loop &, const Rc<DeviceQueue> &)> &&a, Function<void(Loop &)> &&r,
72 : Loop *h, Rc<Ref> &&ref)
73 0 : : acquireForLoop(move(a)), releaseForLoop(move(r)), loop(h), ref(move(ref)) { }
74 : };
75 :
76 : uint32_t index;
77 : uint32_t count;
78 : QueueOperations preferred = QueueOperations::None;
79 : QueueOperations ops = QueueOperations::None;
80 : VkExtent3D transferGranularity;
81 : Vector<Rc<DeviceQueue>> queues;
82 : Vector<Rc<CommandPool>> pools;
83 : Vector<Waiter> waiters;
84 : };
85 :
86 : class DeviceQueue final : public Ref {
87 : public:
88 : enum class IdleMode {
89 : None,
90 : Queue,
91 : Device
92 : };
93 :
94 : using FrameSync = core::FrameSync;
95 : using FrameHandle = core::FrameHandle;
96 :
97 : virtual ~DeviceQueue();
98 :
99 : virtual bool init(Device &, VkQueue, uint32_t, QueueOperations);
100 :
101 : bool submit(const FrameSync &, Fence &, CommandPool &, SpanView<const CommandBuffer *>, IdleMode = IdleMode::None);
102 : bool submit(Fence &, const CommandBuffer *, IdleMode = IdleMode::None);
103 : bool submit(Fence &, SpanView<const CommandBuffer *>, IdleMode = IdleMode::None);
104 :
105 : void waitIdle();
106 :
107 : uint32_t getActiveFencesCount();
108 : void retainFence(const Fence &);
109 : void releaseFence(const Fence &);
110 :
111 581639 : uint32_t getIndex() const { return _index; }
112 : uint64_t getFrameIndex() const { return _frameIdx; }
113 4640 : VkQueue getQueue() const { return _queue; }
114 : QueueOperations getOps() const { return _ops; }
115 : VkResult getResult() const { return _result; }
116 :
117 : void setOwner(FrameHandle &);
118 : void reset();
119 :
120 : protected:
121 : Device *_device = nullptr;
122 : uint32_t _index = 0;
123 : uint64_t _frameIdx = 0;
124 : QueueOperations _ops = QueueOperations::None;
125 : VkQueue _queue;
126 : std::atomic<uint32_t> _nfences;
127 : VkResult _result = VK_ERROR_UNKNOWN;
128 : };
129 :
130 : enum class BufferLevel {
131 : Primary = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
132 : Secondary = VK_COMMAND_BUFFER_LEVEL_SECONDARY,
133 : };
134 :
135 : struct QueueFamilyTransfer {
136 : uint32_t srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
137 : uint32_t dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
138 : };
139 :
140 : struct ImageMemoryBarrier {
141 210 : ImageMemoryBarrier() = default;
142 :
143 : ImageMemoryBarrier(Image *, VkAccessFlags src, VkAccessFlags dst,
144 : VkImageLayout old, VkImageLayout _new);
145 : ImageMemoryBarrier(Image *, VkAccessFlags src, VkAccessFlags dst,
146 : VkImageLayout old, VkImageLayout _new, VkImageSubresourceRange);
147 : ImageMemoryBarrier(Image *, VkAccessFlags src, VkAccessFlags dst,
148 : VkImageLayout old, VkImageLayout _new, QueueFamilyTransfer);
149 : ImageMemoryBarrier(Image *, VkAccessFlags src, VkAccessFlags dst,
150 : VkImageLayout old, VkImageLayout _new, QueueFamilyTransfer, VkImageSubresourceRange);
151 : ImageMemoryBarrier(const VkImageMemoryBarrier &);
152 :
153 42 : explicit operator bool() const {
154 42 : return srcAccessMask != 0 || dstAccessMask != 0
155 0 : || oldLayout != VK_IMAGE_LAYOUT_UNDEFINED || newLayout != VK_IMAGE_LAYOUT_UNDEFINED
156 84 : || image != nullptr;
157 : }
158 :
159 : VkAccessFlags srcAccessMask = 0;
160 : VkAccessFlags dstAccessMask = 0;
161 : VkImageLayout oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
162 : VkImageLayout newLayout = VK_IMAGE_LAYOUT_UNDEFINED;
163 : QueueFamilyTransfer familyTransfer;
164 : Image *image = nullptr;
165 : VkImageSubresourceRange subresourceRange;
166 : };
167 :
168 : struct BufferMemoryBarrier {
169 403077 : BufferMemoryBarrier() = default;
170 : BufferMemoryBarrier(Buffer *, VkAccessFlags src, VkAccessFlags dst);
171 : BufferMemoryBarrier(Buffer *, VkAccessFlags src, VkAccessFlags dst,
172 : QueueFamilyTransfer);
173 : BufferMemoryBarrier(Buffer *, VkAccessFlags src, VkAccessFlags dst,
174 : QueueFamilyTransfer, VkDeviceSize, VkDeviceSize);
175 : BufferMemoryBarrier(const VkBufferMemoryBarrier &);
176 :
177 403094 : explicit operator bool() const {
178 403094 : return srcAccessMask != 0 || dstAccessMask != 0 || buffer != nullptr;
179 : }
180 :
181 : VkAccessFlags srcAccessMask = 0;
182 : VkAccessFlags dstAccessMask = 0;
183 : QueueFamilyTransfer familyTransfer;
184 : Buffer *buffer = nullptr;
185 : VkDeviceSize offset = 0;
186 : VkDeviceSize size = VK_WHOLE_SIZE;
187 : };
188 :
189 : struct DescriptorInfo {
190 1609762 : DescriptorInfo(const PipelineDescriptor *desc, uint32_t index, bool external)
191 1609762 : : descriptor(desc), index(index), external(external) { }
192 :
193 : const PipelineDescriptor *descriptor;
194 : uint32_t index;
195 : bool external;
196 : };
197 :
198 : struct DescriptorImageInfo : public DescriptorInfo {
199 : ~DescriptorImageInfo();
200 : DescriptorImageInfo(const PipelineDescriptor *desc, uint32_t index, bool external);
201 :
202 : Rc<ImageView> imageView;
203 : VkSampler sampler = VK_NULL_HANDLE;
204 : VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
205 : };
206 :
207 : struct DescriptorBufferInfo : public DescriptorInfo {
208 : ~DescriptorBufferInfo();
209 : DescriptorBufferInfo(const PipelineDescriptor *desc, uint32_t index, bool external);
210 :
211 : Rc<Buffer> buffer;
212 : VkDeviceSize offset = 0;
213 : VkDeviceSize range = VK_WHOLE_SIZE;
214 : };
215 :
216 : struct DescriptorBufferViewInfo : public DescriptorInfo {
217 : ~DescriptorBufferViewInfo();
218 : DescriptorBufferViewInfo(const PipelineDescriptor *desc, uint32_t index, bool external);
219 :
220 : Rc<Buffer> buffer;
221 : VkBufferView target = VK_NULL_HANDLE;
222 : };
223 :
224 : class CommandBuffer : public core::CommandBuffer {
225 : public:
226 : virtual ~CommandBuffer();
227 :
228 : bool init(const CommandPool *, const DeviceTable *, VkCommandBuffer);
229 : void invalidate();
230 :
231 : void cmdPipelineBarrier(VkPipelineStageFlags, VkPipelineStageFlags, VkDependencyFlags,
232 : SpanView<ImageMemoryBarrier>);
233 : void cmdPipelineBarrier(VkPipelineStageFlags, VkPipelineStageFlags, VkDependencyFlags,
234 : SpanView<BufferMemoryBarrier>);
235 : void cmdPipelineBarrier(VkPipelineStageFlags, VkPipelineStageFlags, VkDependencyFlags,
236 : SpanView<BufferMemoryBarrier>, SpanView<ImageMemoryBarrier>);
237 :
238 : void cmdCopyBuffer(Buffer *src, Buffer *dst);
239 : void cmdCopyBuffer(Buffer *src, Buffer *dst, VkDeviceSize srcOffset, VkDeviceSize dstOffset, VkDeviceSize size);
240 : void cmdCopyBuffer(Buffer *src, Buffer *dst, SpanView<VkBufferCopy>);
241 :
242 : void cmdCopyImage(Image *src, VkImageLayout, Image *dst, VkImageLayout, VkFilter filter = VK_FILTER_LINEAR);
243 : void cmdCopyImage(Image *src, VkImageLayout, Image *dst, VkImageLayout, const VkImageCopy ©);
244 : void cmdCopyImage(Image *src, VkImageLayout, Image *dst, VkImageLayout, SpanView<VkImageCopy>);
245 :
246 : void cmdCopyBufferToImage(Buffer *, Image *, VkImageLayout, VkDeviceSize offset);
247 : void cmdCopyBufferToImage(Buffer *, Image *, VkImageLayout, SpanView<VkBufferImageCopy>);
248 :
249 : void cmdCopyImageToBuffer(Image *, VkImageLayout, Buffer *buf, VkDeviceSize offset);
250 : void cmdCopyImageToBuffer(Image *, VkImageLayout, Buffer *buf, SpanView<VkBufferImageCopy>);
251 :
252 : void cmdClearColorImage(Image *, VkImageLayout, const Color4F &);
253 :
254 : void cmdBeginRenderPass(RenderPass *pass, Framebuffer *fb, VkSubpassContents subpass, bool alt = false);
255 : void cmdEndRenderPass();
256 :
257 : void cmdSetViewport(uint32_t firstViewport, SpanView<VkViewport> viewports);
258 : void cmdSetScissor(uint32_t firstScissor, SpanView<VkRect2D> scissors);
259 :
260 : void cmdBindPipeline(GraphicPipeline *);
261 : void cmdBindPipeline(ComputePipeline *);
262 :
263 : void cmdBindIndexBuffer(Buffer *, VkDeviceSize offset, VkIndexType indexType);
264 :
265 : void cmdBindDescriptorSets(RenderPass *, uint32_t layoutIndex, uint32_t firstSet = 0);
266 : void cmdBindDescriptorSets(RenderPass *, uint32_t layoutIndex, SpanView<VkDescriptorSet>, uint32_t firstSet = 0);
267 :
268 : void cmdBindGraphicDescriptorSets(VkPipelineLayout, SpanView<VkDescriptorSet>, uint32_t firstSet = 0);
269 : void cmdBindComputeDescriptorSets(VkPipelineLayout, SpanView<VkDescriptorSet>, uint32_t firstSet = 0);
270 :
271 : void cmdDraw(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance);
272 : void cmdDrawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex,
273 : int32_t vertexOffset, uint32_t firstInstance);
274 :
275 : void cmdPushConstants(VkPipelineLayout layout, VkShaderStageFlags stageFlags, uint32_t offset, BytesView);
276 : void cmdPushConstants(VkShaderStageFlags stageFlags, uint32_t offset, BytesView);
277 :
278 : void cmdFillBuffer(Buffer *, uint32_t data);
279 : void cmdFillBuffer(Buffer *, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data);
280 :
281 : // count in group blocks
282 : void cmdDispatch(uint32_t groupCountX, uint32_t groupCountY = 1, uint32_t groupCountZ = 1);
283 :
284 : // count in individual elements, not in blocks
285 : void cmdDispatchPipeline(ComputePipeline *, uint32_t countX, uint32_t countY = 1, uint32_t countZ = 1);
286 :
287 : uint32_t cmdNextSubpass();
288 :
289 395916 : VkCommandBuffer getBuffer() const { return _buffer; }
290 :
291 : uint32_t getCurrentSubpass() const { return _currentSubpass; }
292 : uint32_t getBoundLayoutIndex() const { return _boundLayoutIndex; }
293 : VkPipelineLayout getBoundLayout() const { return _boundLayout; }
294 :
295 : void writeImageTransfer(uint32_t sourceFamily, uint32_t targetFamily, const Rc<Buffer> &, const Rc<Image> &);
296 :
297 : virtual void bindBuffer(core::BufferObject *) override;
298 :
299 : protected:
300 : VkPipelineLayout _boundLayout = VK_NULL_HANDLE;
301 :
302 : const CommandPool *_pool = nullptr;
303 : const DeviceTable *_table = nullptr;
304 : VkCommandBuffer _buffer = VK_NULL_HANDLE;
305 :
306 : Set<Rc<DescriptorSet>> _descriptorSets;
307 : Set<Rc<DeviceMemoryPool>> _memPool;
308 : };
309 :
310 : class CommandPool : public Ref {
311 : public:
312 : static constexpr VkCommandBufferUsageFlagBits DefaultFlags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
313 :
314 : using Level = BufferLevel;
315 :
316 : virtual ~CommandPool();
317 :
318 : bool init(Device &dev, uint32_t familyIdx, QueueOperations c = QueueOperations::Graphics, bool transient = true);
319 : void invalidate(Device &dev);
320 :
321 2428 : QueueOperations getClass() const { return _class; }
322 265498 : uint32_t getFamilyIdx() const { return _familyIdx; }
323 : VkCommandPool getCommandPool() const { return _commandPool; }
324 :
325 : const CommandBuffer * recordBuffer(Device &dev, const Callback<bool(CommandBuffer &)> &,
326 : VkCommandBufferUsageFlagBits = DefaultFlags, Level = Level::Primary);
327 :
328 : void freeDefaultBuffers(Device &dev, Vector<VkCommandBuffer> &);
329 : void reset(Device &dev, bool release = false);
330 :
331 : void autorelease(Rc<Ref> &&);
332 :
333 : protected:
334 : uint32_t _familyIdx = 0;
335 : uint32_t _currentComplexity = 0;
336 : uint32_t _bestComplexity = 0;
337 : QueueOperations _class = QueueOperations::Graphics;
338 : VkCommandPool _commandPool = VK_NULL_HANDLE;
339 : Vector<Rc<Ref>> _autorelease;
340 : Vector<Rc<CommandBuffer>> _buffers;
341 : };
342 :
343 : }
344 :
345 : #endif /* XENOLITH_BACKEND_VK_XLVKDEVICEQUEUE_H_ */
|