1 module sbylib.wrapper.vulkan.util; 2 3 import std; 4 import erupted; 5 import sbylib.wrapper.vulkan; 6 7 struct VkProp { 8 string[] names; 9 } 10 11 VkProp vkProp(string[] names...) { 12 return VkProp(names); 13 } 14 15 // ex) uint -> uint 16 Dst convFrom(Dst)(Dst t) if (isBasicType!Dst) { 17 return t; 18 } 19 20 // ex) VkMemoryType -> VkMemoryType 21 Dst convFrom(Dst)(Dst t) if (is(Dst == struct)) { 22 return t; 23 } 24 25 // ex) char[256] -> immutable(string) 26 Dst convFrom(Dst: string, uint N)(char[N] src) { 27 return fromStringz(src.ptr).idup; 28 } 29 30 // ex) uint -> BitFlags!Flags 31 Dst convFrom(Dst, Src)(Src src) if (isInstanceOf!(BitFlags, Dst)) { 32 Dst result; 33 static if (is(Dst == BitFlags!Enum, Enum)) { 34 static foreach (mem; EnumMembers!Enum) { 35 if (src & mem) { 36 result |= mem; 37 } 38 } 39 } else { 40 static assert(false); 41 } 42 return result; 43 } 44 45 // ex) (VkMemoryType[32], uint) -> const(VkMemoryType)[] 46 Dst construct(Dst, Src, uint N, Length)(Src[N] src, Length len) if (isDynamicArray!(Dst)) 47 in (len < N) 48 { 49 alias DstE = Unqual!(ForeachType!(Dst)); 50 51 DstE[] result = new DstE[len]; 52 foreach (i; 0..len) { 53 result[i] = convFrom!DstE(src[i]); 54 } 55 return result; 56 } 57 58 // ex) VkMemoryHeap -> MemoryHeap 59 Dst convFrom(Dst, Src)(Src src) if (is(Src == struct) && is(Dst == struct) && !is(Src == Dst)) { 60 return Dst(src); 61 } 62 63 // ex) VkSurfaceTransformFlagBitsKHR -> SurfaceTransform 64 Dst convFrom(Dst, Src)(Src src) if (is(Src == enum) && is(Dst == enum) && !is(Src == Dst)) { 65 return src.to!(OriginalType!Src).to!(Dst); 66 } 67 68 // ex) uint -> uint 69 Dst convTo(Dst)(Dst t) if (isBasicType!Dst) { 70 return t; 71 } 72 73 // ex) VkRect2D -> VkRect2D 74 Dst convTo(Dst)(Dst t) if (is(Dst == struct)) { 75 return t; 76 } 77 78 // ex) VkClearValue -> VkClearValue 79 Dst convTo(Dst)(Dst t) if (is(Dst == union)) { 80 return t; 81 } 82 83 // ex) const(VkPhysicalDeviceFeatures)* -> const(VkPhysicalDeviceFeatures*) 84 Dst convTo(Dst)(Dst t) if (isPointer!Dst) { 85 return t; 86 } 87 88 // ex) immutable(float[4]) -> float[4] 89 Dst convTo(Dst)(Dst t) if (isStaticArray!Dst) { 90 return t; 91 } 92 93 // ex) CommandPool -> VkCommandPool 94 Dst convTo(Dst, Src)(Src src) if (is(Src == class) && hasMember!(Src, "vkTo") && isPointer!(Dst)) { 95 if (src is null) return null; 96 97 return src.vkTo(); 98 } 99 100 101 // ex) CommandBuffer.InheritanceInfo -> VkCommandBufferInheritanceInfo 102 Dst convTo(Dst, Src)(Src src) if (is(Src == struct) && is(Dst == struct) && hasMember!(Src, "vkTo")) { 103 return src.vkTo(); 104 } 105 106 // ex) CommandBuffer.InheritanceInfo -> const(VkCommandBufferInheritanceInfo)* 107 Dst convTo(Dst, Src)(Src src) if (is(Src == struct) && isPointer!(Dst)) { 108 alias DstE = Unqual!(PointerTarget!Dst); 109 110 DstE* tmp = new DstE; 111 *tmp = convTo!(DstE)(src); 112 return tmp; 113 } 114 115 // ex) immutable BitFlags!(Flags) -> uint 116 Dst convTo(Dst, Src)(Src src) if (isInstanceOf!(BitFlags, Src)) { 117 static if (is(Src == BitFlags!Enum, Enum)) { 118 return to!Dst(cast(OriginalType!Enum)src); 119 } else { 120 static assert(false); 121 } 122 } 123 124 // ex) const(string) -> const(char)* 125 Dst convTo(Dst)(const string src) { 126 return src.toStringz(); 127 } 128 129 // ex) const(uint[]) -> (uint*, uint) 130 Tuple!(Dst*, Length) destruct(Dst, Length, Src)(Src[] src) if (is(Src == Dst)) { 131 return tuple(src.ptr, cast(Length) src.length); 132 } 133 134 // ex) const(QueueCreateInfo[]) -> (VkDeviceQueueCreateInfo*, uint) 135 Tuple!(Dst*, Length) destruct(Dst, Length, Src)(const Src[] src) 136 if (!is(Src == Dst) && !isBasicType!Src && !isBasicType!Dst) 137 { 138 Dst[] dst = new Dst[src.length]; 139 foreach (i; 0 .. src.length) { 140 dst[i] = convTo!(Dst)(src[i]); 141 } 142 return tuple(dst.ptr, cast(Length) dst.length); 143 } 144 145 // ex) ShaderStageCreateInfo -> (VkPipelineShaderStageCreateInfo, uint) 146 Tuple!(Dst*, Length) destruct(Dst, Length, Src)(Src[] src) 147 if (!is(Src == Dst) && !isBasicType!Src && !isBasicType!Dst) 148 { 149 Dst[] dst = new Dst[src.length]; 150 foreach (i; 0 .. src.length) { 151 dst[i] = convTo!(Dst)(src[i]); 152 } 153 return tuple(dst.ptr, cast(Length) dst.length); 154 } 155 156 // ex) ubyte[] -> (uint*, size_t) 157 Tuple!(Dst*, Length) destruct(Dst, Length, Src)(Src[] src) 158 if (!is(Src == Dst) && isBasicType!Src && isBasicType!Dst) 159 { 160 return tuple(cast(Dst*)src.ptr, cast(Length) src.length); 161 } 162 163 mixin template VkFrom(OriginalType) { 164 import std; 165 import sbylib.wrapper.vulkan.util; 166 167 this(OriginalType orig) { 168 static foreach (name; VkPropertyNames!(typeof(this))) { 169 { 170 alias Dst = Unqual!(typeof(mixin("this.", name))); 171 alias props = getUDAs!(mixin("this.", name), VkProp); 172 static assert(props.length == 1); 173 enum names = props[0].names; 174 175 static if (names.length > 0) { 176 auto tmp = mixin("tuple(", names.map!(n => "orig." ~ n).join(","), ")"); 177 mixin("this.", name) = construct!(Dst)(tmp.expand); 178 } else { 179 mixin("this.", name) = convFrom!(Dst)(mixin("orig.", name)); 180 } 181 } 182 } 183 } 184 } 185 186 mixin template VkTo(OriginalType) { 187 import std; 188 import sbylib.wrapper.vulkan.util; 189 190 template hasOriginalType(string[] members) { 191 static if (members.length == 0) 192 enum hasOriginalType = false; 193 else static if (is(typeof(__traits(getMember, typeof(this), members[0])) == OriginalType)) 194 enum hasOriginalType = true; 195 else 196 enum hasOriginalType = hasOriginalType!(members[1 .. $]); 197 } 198 199 static if (hasOriginalType!([__traits(allMembers, typeof(this))])) { 200 inout(OriginalType) vkTo() inout { 201 static foreach (mem; FieldNameTuple!(typeof(this))) { 202 static if (is(typeof(mixin("this.", mem)) == inout(OriginalType))) { 203 return mixin("this.", mem); 204 } 205 } 206 } 207 } else { 208 OriginalType vkTo() { 209 OriginalType orig; 210 static foreach (name; VkPropertyNames!(typeof(this))) { 211 { 212 alias Src = typeof(mixin("this.", name)); 213 214 alias props = getUDAs!(mixin("this.", name), VkProp); 215 static assert(props.length == 1); 216 217 enum names = props[0].names; 218 219 static if (names.length == 2) { 220 static assert(isArray!(Src)); 221 222 alias DstPtr = typeof(mixin("orig.", names[0])); 223 alias Length = typeof(mixin("orig.", names[1])); 224 225 static assert(isPointer!(DstPtr)); 226 alias Dst = Unqual!(PointerTarget!(DstPtr)); 227 228 auto tmp = destruct!(Dst, Length)(mixin("this.", name)); 229 mixin("orig.", names[0]) = tmp[0]; 230 231 if (tmp[1] > 0 && mixin("orig.", names[1]) == 0) { 232 mixin("orig.", names[1]) = tmp[1]; // for avoiding double assignment 233 } 234 } else static if (names.length == 1) { 235 alias Dst = typeof(mixin("orig.", names[0])); 236 static if (isDynamicArray!(Src) && isPointer!(Dst)) { 237 auto tmp = destruct!(Unqual!(PointerTarget!Dst), uint)(mixin("this.", name)); 238 mixin("orig.", names[0]) = tmp[0]; 239 } else { 240 mixin("orig.", names[0]) = convTo!(Dst)(mixin("this.", name)); 241 } 242 } else static if (names.length == 0) { 243 alias Dst = typeof(mixin("orig.", name)); 244 mixin("orig.", name) = convTo!(Dst)(mixin("this.", name)); 245 } else { 246 static assert(false); 247 } 248 } 249 } 250 return orig; 251 } 252 } 253 } 254 255 mixin template ImplToString() { 256 import std; 257 import std : format; 258 259 string toString() const { 260 261 enum names = VkPropertyNames!(typeof(this)); 262 263 enum L = names.map!(n => n.length).maxElement; 264 265 string[] fields; 266 static foreach (name; names) { 267 { 268 static if (is(Unqual!(typeof(mixin("this.", name))) == BitFlags!E, E)) { 269 fields ~= format!("%" ~ L.to!string ~ "s: %s")(name, 270 [EnumMembers!E].filter!(m => cast(bool)(mixin("this.", name) & m)) 271 .map!(to!string) 272 .join(" | ")); 273 } else { 274 fields ~= format!("%" ~ L.to!string ~ "s: %s")(name, 275 mixin("this.", name).to!string); 276 } 277 } 278 } 279 280 return format!"%s {\n%s\n}"(Unqual!(typeof(this)).stringof, 281 fields.map!(txt => " " ~ txt).join("\n")); 282 } 283 } 284 285 template VkPropertyNames(This) { 286 import std; 287 288 private enum isVkProp(string name) = hasUDA!(__traits(getMember, This, name), VkProp); 289 static immutable VkPropertyNames = [ 290 Filter!(isVkProp, FieldNameTuple!(This)) 291 ]; 292 } 293 294 void enforceVK(VkResult res) { 295 enforce(res == VkResult.VK_SUCCESS, res.to!string); 296 } 297 298 void compileShader(string filename) { 299 const result = executeShell("glslangValidator -e main -V " ~ filename); 300 assert(result.status == 0, result.output); 301 } 302 303 mixin template ImplNameSetter(alias device, alias obj, DebugReportObjectType type) { 304 import std : toStringz; 305 306 void name(string n) { 307 VkDebugMarkerObjectNameInfoEXT info = { 308 objectType: type, 309 object: cast(ulong)obj, 310 pObjectName: n.toStringz() 311 }; 312 enforceVK(vkDebugMarkerSetObjectNameEXT(device.device, &info)); 313 } 314 }