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 }