SPARK  0.1.0
A general purpose game engine written in C++.
Loading...
Searching...
No Matches
DescriptorSet.h
1#pragma once
2
3#include "spark/render/Buffer.h"
4#include "spark/render/DescriptorBinding.h"
5#include "spark/render/Export.h"
6#include "spark/render/Sampler.h"
7#include "spark/render/ShaderStages.h"
8
9#include <algorithm>
10#include <memory>
11
12namespace spark::render
13{
18 enum class DescriptorType
19 {
20 // ReSharper disable CppInconsistentNaming
21
23 ConstantBuffer = 0x00000001,
24
28 StructuredBuffer = 0x00000002,
29
31 RWStructuredBuffer = 0x00000012,
32
36 Texture = 0x00000003,
37
39 RWTexture = 0x00000013,
40
42 Sampler = 0x00000004,
43
45 InputAttachment = 0x00000005,
46
48 Buffer = 0x00000006,
49
51 RWBuffer = 0x00000016,
52
54 ByteAddressBuffer = 0x00000007,
55
57 RWByteAddressBuffer = 0x00000017,
58
59 // ReSharper restore CppInconsistentNaming
60 };
61
73 class SPARK_RENDER_EXPORT IDescriptorLayout : public IBufferLayout
74 {
75 public:
76 ~IDescriptorLayout() noexcept override = default;
77
82 [[nodiscard]] virtual DescriptorType descriptorType() const noexcept = 0;
83
90 [[nodiscard]] virtual unsigned int descriptors() const noexcept = 0;
91
96 [[nodiscard]] virtual const ISampler* staticSampler() const noexcept = 0;
97 };
98
102 class SPARK_RENDER_EXPORT IDescriptorSet
103 {
104 public:
105 virtual ~IDescriptorSet() noexcept = default;
106
115 void update(unsigned int binding, const IBuffer& buffer, unsigned int buffer_element = 0, unsigned int elements = 0, unsigned int first_descriptor = 0) const
116 {
117 genericUpdate(binding, buffer, buffer_element, elements, first_descriptor);
118 }
119
130 void update(unsigned int binding,
131 const IImage& texture,
132 unsigned int descriptor = 0,
133 unsigned int first_level = 0,
134 unsigned int levels = 0,
135 unsigned int first_layer = 0,
136 unsigned int layers = 0) const { genericUpdate(binding, texture, descriptor, first_level, levels, first_layer, layers); }
137
144 void update(unsigned int binding, const ISampler& sampler, unsigned int descriptor = 0) const { genericUpdate(binding, sampler, descriptor); }
145
151 void attach(unsigned int binding, const IImage& image) const { genericAttach(binding, image); }
152
153 private:
156 virtual void genericUpdate(unsigned int binding, const IBuffer& buffer, unsigned int buffer_element, unsigned int elements, unsigned int first_descriptor) const = 0;
157 virtual void genericUpdate(unsigned int binding,
158 const IImage& texture,
159 unsigned int descriptor,
160 unsigned int first_level,
161 unsigned int levels,
162 unsigned int first_layer,
163 unsigned int layers) const = 0;
164 virtual void genericUpdate(unsigned int binding, const ISampler& sampler, unsigned int descriptor) const = 0;
165 virtual void genericAttach(unsigned int binding, const IImage& image) const = 0;
167 };
168
209 template <typename BufferType, typename ImageType, typename SamplerType>
211 {
212 public:
213 using buffer_type = BufferType;
214 using image_type = ImageType;
215 using sampler_type = SamplerType;
216
217 public:
219 virtual void update(unsigned int binding,
220 const buffer_type& buffer,
221 unsigned int buffer_element = 0,
222 unsigned int elements = 0,
223 unsigned int first_descriptor = 0) const = 0;
224
226 virtual void update(unsigned int binding,
227 const image_type& texture,
228 unsigned int descriptor = 0,
229 unsigned int first_level = 0,
230 unsigned int levels = 0,
231 unsigned int first_layer = 0,
232 unsigned int layers = 0) const = 0;
233
235 virtual void update(unsigned int binding, const sampler_type& sampler, unsigned int descriptor = 0) const = 0;
236
238 virtual void attach(unsigned int binding, const image_type& image) const = 0;
239
240 private:
241 void genericUpdate(unsigned binding, const IBuffer& buffer, unsigned buffer_element, unsigned elements, unsigned first_descriptor) const final
242 {
243 update(binding, dynamic_cast<const buffer_type&>(buffer), buffer_element, elements, first_descriptor);
244 }
245
246 void genericUpdate(unsigned binding,
247 const IImage& texture,
248 unsigned descriptor,
249 unsigned first_level,
250 unsigned levels,
251 unsigned first_layer,
252 unsigned layers) const override { update(binding, dynamic_cast<const image_type&>(texture), descriptor, first_level, levels, first_layer, layers); }
253
254 void genericUpdate(unsigned binding, const ISampler& sampler, unsigned descriptor) const final { update(binding, dynamic_cast<const sampler_type&>(sampler), descriptor); }
255 void genericAttach(unsigned binding, const IImage& image) const final { attach(binding, dynamic_cast<const image_type&>(image)); }
256 };
257
261 class SPARK_RENDER_EXPORT IDescriptorSetLayout
262 {
263 public:
264 virtual ~IDescriptorSetLayout() noexcept = default;
265
270 [[nodiscard]] std::vector<const IDescriptorLayout*> descriptors() const noexcept { return genericDescriptors(); }
271
277 [[nodiscard]] virtual const IDescriptorLayout* descriptor(unsigned int binding) const = 0;
278
285 [[nodiscard]] virtual unsigned int space() const noexcept = 0;
286
291 [[nodiscard]] virtual ShaderStage shaderStage() const noexcept = 0;
292
297 [[nodiscard]] virtual unsigned int uniforms() const noexcept = 0;
298
303 [[nodiscard]] virtual unsigned int storages() const noexcept = 0;
304
309 [[nodiscard]] virtual unsigned int images() const noexcept = 0;
310
315 [[nodiscard]] virtual unsigned int buffers() const noexcept = 0;
316
321 [[nodiscard]] virtual unsigned int samplers() const noexcept = 0;
322
327 [[nodiscard]] virtual unsigned int staticSamplers() const noexcept = 0;
328
333 [[nodiscard]] virtual unsigned int inputAttachments() const noexcept = 0;
334
359 [[nodiscard]] std::unique_ptr<IDescriptorSet> allocate(const std::vector<DescriptorBinding>& bindings = {}) const { return genericAllocate(0, bindings); }
360
367 [[nodiscard]] std::unique_ptr<IDescriptorSet> allocate(unsigned int descriptors, const std::vector<DescriptorBinding>& bindings = {}) const
368 {
369 return genericAllocate(descriptors, bindings);
370 }
371
378 [[nodiscard]] std::vector<std::unique_ptr<IDescriptorSet>> allocateMultiple(unsigned int descriptors_sets,
379 const std::vector<std::vector<DescriptorBinding>>& bindings = {}) const noexcept
380 {
381 return allocateMultiple(descriptors_sets, 0, bindings);
382 }
383
390 [[nodiscard]] std::vector<std::unique_ptr<IDescriptorSet>> allocateMultiple(unsigned int descriptors_sets,
391 const std::function<std::vector<DescriptorBinding>(unsigned)>& binding_factory) const noexcept
392 {
393 return allocateMultiple(descriptors_sets, 0, binding_factory);
394 }
395
403 [[nodiscard]] std::vector<std::unique_ptr<IDescriptorSet>> allocateMultiple(unsigned int descriptors_sets,
404 unsigned int descriptors,
405 const std::vector<std::vector<DescriptorBinding>>& bindings = {}) const noexcept
406 {
407 return genericAllocate(descriptors_sets, descriptors, bindings);
408 }
409
417 [[nodiscard]] std::vector<std::unique_ptr<IDescriptorSet>> allocateMultiple(unsigned int descriptors_sets,
418 unsigned int descriptors,
419 const std::function<std::vector<DescriptorBinding>(unsigned)>& binding_factory = {}) const
420 noexcept { return genericAllocate(descriptors_sets, descriptors, binding_factory); }
421
426 void free(const IDescriptorSet& descriptor_set) const noexcept { genericFree(descriptor_set); }
427
428 private:
431 [[nodiscard]] virtual std::vector<const IDescriptorLayout*> genericDescriptors() const noexcept = 0;
432 [[nodiscard]] virtual std::unique_ptr<IDescriptorSet> genericAllocate(unsigned int descriptors, const std::vector<DescriptorBinding>& bindings) const noexcept = 0;
433 [[nodiscard]] virtual std::vector<std::unique_ptr<IDescriptorSet>> genericAllocate(unsigned descriptor_sets,
434 unsigned descriptors,
435 const std::vector<std::vector<DescriptorBinding>>& bindings) const = 0;
436 [[nodiscard]] virtual std::vector<std::unique_ptr<IDescriptorSet>> genericAllocate(unsigned descriptor_sets,
437 unsigned descriptors,
438 const std::function<std::vector<DescriptorBinding>(unsigned)>& binding_factory) const =
439 0;
440 virtual void genericFree(const IDescriptorSet& descriptor_set) const noexcept = 0;
442 };
443
449 template <typename DescriptorLayoutType, typename DescriptorSetType>
451 {
452 public:
453 using descriptor_layout_type = DescriptorLayoutType;
454 using descriptor_set_type = DescriptorSetType;
455
456 public:
458 [[nodiscard]] virtual std::vector<const descriptor_layout_type*> descriptors() const noexcept = 0;
459
461 [[nodiscard]] const descriptor_layout_type* descriptor(unsigned binding) const override = 0;
462
464 [[nodiscard]] virtual std::unique_ptr<descriptor_set_type> allocate(const std::vector<DescriptorBinding>& bindings = {}) const = 0;
465
467 [[nodiscard]] virtual std::unique_ptr<descriptor_set_type> allocate(unsigned descriptors, const std::vector<DescriptorBinding>& bindings = { }) const = 0;
468
470 [[nodiscard]] virtual std::vector<std::unique_ptr<descriptor_set_type>> allocateMultiple(unsigned descriptor_sets, const std::vector<std::vector<DescriptorBinding>>& bindings = { }) const = 0;
471
473 [[nodiscard]] virtual std::vector<std::unique_ptr<descriptor_set_type>> allocateMultiple(unsigned descriptor_sets, const std::function<std::vector<DescriptorBinding>(unsigned)>& binding_factory) const = 0;
474
476 [[nodiscard]] virtual std::vector<std::unique_ptr<descriptor_set_type>> allocateMultiple(unsigned descriptor_sets, unsigned descriptors, const std::vector<std::vector<DescriptorBinding>>& bindings = { }) const = 0;
477
479 [[nodiscard]] virtual std::vector<std::unique_ptr<descriptor_set_type>> allocateMultiple(unsigned descriptor_sets, unsigned descriptors, const std::function<std::vector<DescriptorBinding>(unsigned)>& binding_factory) const = 0;
480
482 virtual void free(const descriptor_set_type& descriptor_set) const noexcept = 0;
483
484 private:
485 [[nodiscard]] std::vector<const IDescriptorLayout*> genericDescriptors() const noexcept final
486 {
487 auto tmp = descriptors();
488 std::vector<const IDescriptorLayout*> result;
489 result.reserve(tmp.size());
490 std::ranges::transform(tmp, std::back_inserter(result), [](auto& ptr) { return static_cast<const IDescriptorLayout*>(ptr); });
491 return result;
492 }
493
494 [[nodiscard]] std::unique_ptr<IDescriptorSet> genericAllocate(unsigned descriptors, const std::vector<DescriptorBinding>& bindings) const noexcept final
495 {
496 return allocate(descriptors, bindings);
497 }
498
499 [[nodiscard]] std::vector<std::unique_ptr<IDescriptorSet>> genericAllocate(unsigned descriptor_sets,
500 unsigned descriptors,
501 const std::vector<std::vector<DescriptorBinding>>& bindings) const final
502 {
503 auto tmp = allocateMultiple(descriptor_sets, descriptors, bindings);
504 std::vector<std::unique_ptr<IDescriptorSet>> result;
505 result.reserve(tmp.size());
506 std::ranges::transform(tmp, std::back_inserter(result), [](auto& ptr) { return std::unique_ptr<IDescriptorSet>(ptr.release()); });
507 return result;
508 }
509
510 [[nodiscard]] std::vector<std::unique_ptr<IDescriptorSet>> genericAllocate(unsigned descriptor_sets,
511 unsigned descriptors,
512 const std::function<std::vector<DescriptorBinding>(unsigned)>& binding_factory) const final
513 {
514 auto tmp = allocateMultiple(descriptor_sets, descriptors, binding_factory);
515 std::vector<std::unique_ptr<IDescriptorSet>> result;
516 result.reserve(tmp.size());
517 std::ranges::transform(tmp, std::back_inserter(result), [](auto& ptr) { return std::unique_ptr<IDescriptorSet>(ptr.release()); });
518 return result;
519 }
520
521 void genericFree(const IDescriptorSet& descriptor_set) const noexcept final { free(dynamic_cast<const descriptor_set_type&>(descriptor_set)); }
522 };
523}
524
525template <>
526struct std::formatter<spark::render::DescriptorType> : std::formatter<std::string_view>
527{
528 static constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
529
530 static constexpr auto format(const spark::render::DescriptorType type, auto& ctx)
531 {
532 switch (type)
533 {
534 case spark::render::DescriptorType::ConstantBuffer:
535 return std::format_to(ctx.out(), "ConstantBuffer");
536 case spark::render::DescriptorType::StructuredBuffer:
537 return std::format_to(ctx.out(), "StructuredBuffer");
538 case spark::render::DescriptorType::RWStructuredBuffer:
539 return std::format_to(ctx.out(), "RWStructuredBuffer");
540 case spark::render::DescriptorType::Texture:
541 return std::format_to(ctx.out(), "Texture");
542 case spark::render::DescriptorType::RWTexture:
543 return std::format_to(ctx.out(), "RWTexture");
544 case spark::render::DescriptorType::Sampler:
545 return std::format_to(ctx.out(), "Sampler");
546 case spark::render::DescriptorType::InputAttachment:
547 return std::format_to(ctx.out(), "InputAttachment");
548 case spark::render::DescriptorType::Buffer:
549 return std::format_to(ctx.out(), "Buffer");
550 case spark::render::DescriptorType::RWBuffer:
551 return std::format_to(ctx.out(), "RWBuffer");
552 case spark::render::DescriptorType::ByteAddressBuffer:
553 return std::format_to(ctx.out(), "ByteAddressBuffer");
554 case spark::render::DescriptorType::RWByteAddressBuffer:
555 return std::format_to(ctx.out(), "RWByteAddressBuffer");
556 }
557 return std::format_to(ctx.out(), "Unknown");
558 }
559};
Describes the layout of a descriptor set.
Definition DescriptorSet.h:451
virtual std::vector< std::unique_ptr< descriptor_set_type > > allocateMultiple(unsigned descriptor_sets, unsigned descriptors, const std::function< std::vector< DescriptorBinding >(unsigned)> &binding_factory) const =0
Allocates an array of IDescriptorSet.
virtual std::unique_ptr< descriptor_set_type > allocate(unsigned descriptors, const std::vector< DescriptorBinding > &bindings={ }) const =0
Allocates a new IDescriptorSet or returns an unused descriptor set.
virtual void free(const descriptor_set_type &descriptor_set) const noexcept=0
Marks a IDescriptorSet as unused, so that it can be handed out again instead of allocating a new one.
virtual std::vector< std::unique_ptr< descriptor_set_type > > allocateMultiple(unsigned descriptor_sets, const std::function< std::vector< DescriptorBinding >(unsigned)> &binding_factory) const =0
Allocates an array of IDescriptorSet.
virtual std::vector< const descriptor_layout_type * > descriptors() const noexcept=0
Gets the layouts of all descriptors in the IDescriptorSet.
virtual std::vector< std::unique_ptr< descriptor_set_type > > allocateMultiple(unsigned descriptor_sets, const std::vector< std::vector< DescriptorBinding > > &bindings={ }) const =0
Allocates an array of IDescriptorSet.
virtual std::vector< std::unique_ptr< descriptor_set_type > > allocateMultiple(unsigned descriptor_sets, unsigned descriptors, const std::vector< std::vector< DescriptorBinding > > &bindings={ }) const =0
Allocates an array of IDescriptorSet.
Defines a set of descriptors.
Definition DescriptorSet.h:211
virtual void update(unsigned int binding, const buffer_type &buffer, unsigned int buffer_element=0, unsigned int elements=0, unsigned int first_descriptor=0) const =0
Updates a constant buffer within the IDescriptorSet.
virtual void update(unsigned int binding, const image_type &texture, unsigned int descriptor=0, unsigned int first_level=0, unsigned int levels=0, unsigned int first_layer=0, unsigned int layers=0) const =0
Updates a constant buffer within the IDescriptorSet.
virtual void attach(unsigned int binding, const image_type &image) const =0
Attaches an image as an input attachment to a descriptor bound at binding.
virtual void update(unsigned int binding, const sampler_type &sampler, unsigned int descriptor=0) const =0
Updates a constant buffer within the IDescriptorSet.
Describes the layout of a buffer.
Definition Buffer.h:166
Base interface for all buffers.
Definition Buffer.h:151
Describes a the layout of a single descriptor within a DescriptorSet.
Definition DescriptorSet.h:74
virtual DescriptorType descriptorType() const noexcept=0
Gets the type of the descriptor.
Interface for a descriptor set layout.
Definition DescriptorSet.h:262
std::vector< std::unique_ptr< IDescriptorSet > > allocateMultiple(unsigned int descriptors_sets, const std::function< std::vector< DescriptorBinding >(unsigned)> &binding_factory) const noexcept
Allocates an array of IDescriptorSet.
Definition DescriptorSet.h:390
void free(const IDescriptorSet &descriptor_set) const noexcept
Marks a IDescriptorSet as unused, so that it can be handed out again instead of allocating a new one.
Definition DescriptorSet.h:426
std::unique_ptr< IDescriptorSet > allocate(unsigned int descriptors, const std::vector< DescriptorBinding > &bindings={}) const
Allocates a new IDescriptorSet or returns an unused descriptor set.
Definition DescriptorSet.h:367
virtual unsigned int space() const noexcept=0
Gets the space index of the IDescriptorSet.
virtual const IDescriptorLayout * descriptor(unsigned int binding) const =0
Gets the layout of a descriptor in the IDescriptorSet bound to a specific binding point.
std::vector< std::unique_ptr< IDescriptorSet > > allocateMultiple(unsigned int descriptors_sets, const std::vector< std::vector< DescriptorBinding > > &bindings={}) const noexcept
Allocates an array of IDescriptorSet.
Definition DescriptorSet.h:378
std::vector< const IDescriptorLayout * > descriptors() const noexcept
Gets the layouts of all descriptors in the IDescriptorSet.
Definition DescriptorSet.h:270
std::vector< std::unique_ptr< IDescriptorSet > > allocateMultiple(unsigned int descriptors_sets, unsigned int descriptors, const std::function< std::vector< DescriptorBinding >(unsigned)> &binding_factory={}) const noexcept
Allocates an array of IDescriptorSet.
Definition DescriptorSet.h:417
std::vector< std::unique_ptr< IDescriptorSet > > allocateMultiple(unsigned int descriptors_sets, unsigned int descriptors, const std::vector< std::vector< DescriptorBinding > > &bindings={}) const noexcept
Allocates an array of IDescriptorSet.
Definition DescriptorSet.h:403
Interface for a descriptor set.
Definition DescriptorSet.h:103
void attach(unsigned int binding, const IImage &image) const
Attaches an image as an input attachment to a descriptor bound at binding.
Definition DescriptorSet.h:151
void update(unsigned int binding, const ISampler &sampler, unsigned int descriptor=0) const
Updates a sampler within the current descriptor set.
Definition DescriptorSet.h:144
void update(unsigned int binding, const IBuffer &buffer, unsigned int buffer_element=0, unsigned int elements=0, unsigned int first_descriptor=0) const
Updates a constant buffer within the IDescriptorSet.
Definition DescriptorSet.h:115
void update(unsigned int binding, const IImage &texture, unsigned int descriptor=0, unsigned int first_level=0, unsigned int levels=0, unsigned int first_layer=0, unsigned int layers=0) const
Updates a texture within the current descriptor set.
Definition DescriptorSet.h:130
Definition Image.h:131
Describes a texture sampler.
Definition Sampler.h:59
Describes a resource binding in a descriptor set.
Definition DescriptorBinding.h:18