1 module sbylib.graphics.core.descriptor;
2 
3 mixin template Descriptor() {
4     /*
5        UDAs
6      */
7     enum stages;
8     enum vertex;
9     struct binding { int binding; }
10     struct stage { ShaderStage stage; }
11     struct type { DescriptorType type; }
12     enum uniform = type(DescriptorType.UniformBuffer);
13     enum texture = type(DescriptorType.CombinedImageSampler);
14     enum storage = type(DescriptorType.StorageBuffer);
15 
16     mixin template ShaderSource(ShaderStage stage, string code) {
17         import std : to;
18         import std..string : replace;
19         import sbylib.graphics.core.shader : ShaderUtil;
20 
21         mixin(q{
22             private @stages Pipeline.ShaderStageCreateInfo createShaderModule${stage}() {
23                 auto mod = ShaderUtil.createModule(stage, code);
24                 shaderModules ~= mod;
25 
26                 Pipeline.ShaderStageCreateInfo result = {
27                     stage: stage,
28                     pName: "main",
29                     _module: mod
30                 };
31                 return result;
32             }
33         }.replace("${stage}", stage.to!string));
34     }
35 
36     mixin template MaxObjects(size_t n) {
37         private enum maxObjects = n;
38     }
39 
40     /*
41        resources
42      */
43     protected @own {
44         DescriptorSetLayout descriptorSetLayout;
45         DescriptorPool descriptorPool;
46         ShaderModule[] shaderModules;
47     }
48     mixin ImplReleaseOwn;
49 
50 }
51 
52 mixin template ImplDescriptor() {
53     mixin template DefineInstanceMembers(Descriptor) {
54         import sbylib.graphics.util.own : own;
55         import sbylib.graphics.util.member : getMembersByUDA;
56         import sbylib.graphics.wrapper.buffer : VBuffer;
57         import sbylib.graphics.wrapper.texture : Texture;
58         import std : format;
59 
60         static foreach (memberInfo; getMembersByUDA!(Descriptor, type)) {
61             static assert(memberInfo.hasType);
62             static assert(memberInfo.hasAttributes);
63             static if (is(memberInfo.type : Texture)) {
64                 alias Type(alias m : memberInfo) = memberInfo.type;
65             } else {
66                 alias Type(alias m : memberInfo) = VBuffer!(memberInfo.type);
67             }
68             @own @(memberInfo.attributes) mixin(format!q{%s %s;}(Type!(memberInfo).stringof, memberInfo.name));
69         }
70 
71         private void initializeDefinedBuffers() {
72             template getUsage(DescriptorType type) {
73                 static if (type == DescriptorType.UniformBuffer) {
74                     enum getUsage = BufferUsage.UniformBuffer;
75                 } else static if (type == DescriptorType.StorageBuffer) {
76                     enum getUsage = BufferUsage.StorageBuffer;
77                 }
78             }
79             static foreach (memberInfo; getMembersByUDA!(typeof(this), type)) {
80                 static if (isInstanceOf!(VBuffer, memberInfo.type)) {
81                     memberInfo.member = new memberInfo.type([memberInfo.type.Type.init], getUsage!(memberInfo.getUDA!(type).type));
82                 }
83             }
84         }
85 
86         public DescriptorSet createDescriptorSet(DescriptorPool descriptorPool, DescriptorSetLayout descriptorSetLayout) {
87             auto result = allocateDescriptorSet(descriptorPool, descriptorSetLayout);
88             writeDescriptor(result);
89             return result;
90         }
91 
92         private DescriptorSet allocateDescriptorSet(DescriptorPool descriptorPool, DescriptorSetLayout descriptorSetLayout) {
93             DescriptorSet.AllocateInfo descriptorSetAllocInfo = {
94                 descriptorPool: descriptorPool,
95                 setLayouts: [descriptorSetLayout]
96             };
97             return DescriptorSet.allocate(VDevice(), descriptorSetAllocInfo)[0];
98         }
99 
100         private void writeDescriptor(DescriptorSet descriptorSet) {
101             import std : isInstanceOf;
102             enum N = getMembersByUDA!(typeof(this), type).length;
103             static assert(N > 0);
104             DescriptorSet.Write[N] writes;
105 
106             size_t i;
107             static foreach (memberInfo; getMembersByUDA!(typeof(this), type)) {{
108                 static if (isInstanceOf!(VBuffer, memberInfo.type)) {
109                     assert(memberInfo.member, memberInfo.name ~ " is not set.");
110                     assert(memberInfo.member.buffer);
111                     DescriptorSet.Write w = {
112                         dstSet: descriptorSet,
113                         dstBinding: memberInfo.getUDA!(binding).binding,
114                         dstArrayElement: 0,
115                         descriptorType: memberInfo.getUDA!(type).type,
116                         bufferInfo: [{
117                             buffer: memberInfo.member.buffer,
118                             offset: 0,
119                             range: memberInfo.type.Type.sizeof
120                         }]
121                     };
122                     writes[i++] = w;
123                 } else static if (is(memberInfo.type : Texture)) {
124                     assert(memberInfo.member, memberInfo.name.stringof ~ " is not set.");
125                     assert(memberInfo.member.sampler);
126                     assert(memberInfo.member.imageView);
127                     DescriptorSet.Write w = {
128                         dstSet: descriptorSet,
129                         dstBinding: memberInfo.getUDA!(binding).binding,
130                         dstArrayElement: 0,
131                         descriptorType: memberInfo.getUDA!(type).type,
132                         imageInfo: [{
133                             sampler: memberInfo.member.sampler,
134                             imageView: memberInfo.member.imageView,
135                             imageLayout: ImageLayout.ShaderReadOnlyOptimal
136                         }]
137                     };
138                     writes[i++] = w;
139                 }
140             }}
141             assert(i == N);
142             DescriptorSet.Copy[0] copies;
143             descriptorSet.update(writes, copies);
144         }
145     }
146 
147     /*
148        Implementation
149      */
150 
151     private void initializeDescriptor() {
152         this.descriptorSetLayout = createDescriptorSetLayout();
153         this.descriptorPool = createDescriptorPool();
154     }
155 
156     private DescriptorSetLayout createDescriptorSetLayout() {
157         import sbylib.graphics.util.member : getMembers;
158 
159         DescriptorSetLayout.CreateInfo createInfo;
160 
161         static foreach (memberInfo; getMembers!(typeof(this))) {
162             static foreach (binding; memberInfo.getUDAs!(binding)) {
163                 static foreach (type; memberInfo.getUDAs!(type)) {
164                     static foreach (stage; memberInfo.getUDAs!(stage)) {{
165                         DescriptorSetLayout.CreateInfo.Binding b = {
166                             binding: binding.binding,
167                             descriptorType: type.type,
168                             descriptorCount: 1,
169                             stageFlags: stage.stage
170                         };
171                         createInfo.bindings ~= b;
172                     }}
173                 }
174             }
175         }
176 
177         return new DescriptorSetLayout(VDevice(), createInfo);
178     }
179 
180     private DescriptorPool createDescriptorPool() {
181         import sbylib.graphics.util.member : getMembersByUDA;
182 
183         int[DescriptorType] counts;
184         static foreach (memberInfo; getMembersByUDA!(typeof(this), type)) {
185             counts.require(memberInfo.getUDA!(type).type, 0)++;
186         }
187         DescriptorPool.CreateInfo createInfo = {
188             flags: VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, // to free descriptor set
189             maxSets: maxObjects
190         };
191         foreach (type, count; counts) {
192             DescriptorPool.CreateInfo.DescriptorPoolSize size = {
193                 type: type,
194                 descriptorCount: count
195             };
196             createInfo.poolSizes ~= size;
197         }
198         assert(createInfo.poolSizes.length > 0);
199         return new DescriptorPool(VDevice(), createInfo);
200     }
201 }