Vookoo
vku.hpp
1 //
4 //
6 //
9 //
12 //
15 //
17 
18 #ifndef VKU_HPP
19 #define VKU_HPP
20 
21 #include <array>
22 #include <fstream>
23 #include <iostream>
24 #include <unordered_map>
25 #include <vector>
26 #include <thread>
27 #include <chrono>
28 #include <functional>
29 #include <cstddef>
30 
31 #include <vulkan/spirv.hpp11>
32 #include <vulkan/vulkan.hpp>
33 
34 namespace vku {
35 
37 template <class ... Args>
38 std::string format(const char *fmt, Args... args) {
39  int n = snprintf(nullptr, 0, fmt, args...);
40  std::string result(n, '\0');
41  snprintf(&*result.begin(), n+1, fmt, args...);
42  return std::move(result);
43 }
44 
46 inline int findMemoryTypeIndex(const vk::PhysicalDeviceMemoryProperties &memprops, uint32_t memoryTypeBits, vk::MemoryPropertyFlags search) {
47  for (int i = 0; i != memprops.memoryTypeCount; ++i, memoryTypeBits >>= 1) {
48  if (memoryTypeBits & 1) {
49  if ((memprops.memoryTypes[i].propertyFlags & search) == search) {
50  return i;
51  }
52  }
53  }
54  return -1;
55 }
56 
58 inline void executeImmediately(vk::Device device, vk::CommandPool commandPool, vk::Queue queue, const std::function<void (vk::CommandBuffer cb)> &func) {
59  vk::CommandBufferAllocateInfo cbai{ commandPool, vk::CommandBufferLevel::ePrimary, 1 };
60 
61  auto cbs = device.allocateCommandBuffers(cbai);
62  cbs[0].begin(vk::CommandBufferBeginInfo{});
63  func(cbs[0]);
64  cbs[0].end();
65 
66  vk::SubmitInfo submit;
67  submit.commandBufferCount = (uint32_t)cbs.size();
68  submit.pCommandBuffers = cbs.data();
69  queue.submit(submit, vk::Fence{});
70  device.waitIdle();
71 
72  device.freeCommandBuffers(commandPool, cbs);
73 }
74 
76 inline uint32_t mipScale(uint32_t value, uint32_t mipLevel) {
77  return std::max(value >> mipLevel, (uint32_t)1);
78 }
79 
82 inline std::vector<uint8_t> loadFile(const std::string &filename) {
83  std::ifstream is(filename, std::ios::binary|std::ios::ate);
84  std::vector<uint8_t> bytes;
85  if (!is.fail()) {
86  size_t size = is.tellg();
87  is.seekg(0);
88  bytes.resize(size);
89  is.read((char*)bytes.data(), size);
90  }
91  return std::move(bytes);
92 }
93 
95 struct BlockParams {
96  uint8_t blockWidth;
97  uint8_t blockHeight;
98  uint8_t bytesPerBlock;
99 };
100 
102 inline BlockParams getBlockParams(vk::Format format) {
103  switch (format) {
104  case vk::Format::eR4G4UnormPack8: return BlockParams{1, 1, 1};
105  case vk::Format::eR4G4B4A4UnormPack16: return BlockParams{1, 1, 2};
106  case vk::Format::eB4G4R4A4UnormPack16: return BlockParams{1, 1, 2};
107  case vk::Format::eR5G6B5UnormPack16: return BlockParams{1, 1, 2};
108  case vk::Format::eB5G6R5UnormPack16: return BlockParams{1, 1, 2};
109  case vk::Format::eR5G5B5A1UnormPack16: return BlockParams{1, 1, 2};
110  case vk::Format::eB5G5R5A1UnormPack16: return BlockParams{1, 1, 2};
111  case vk::Format::eA1R5G5B5UnormPack16: return BlockParams{1, 1, 2};
112  case vk::Format::eR8Unorm: return BlockParams{1, 1, 1};
113  case vk::Format::eR8Snorm: return BlockParams{1, 1, 1};
114  case vk::Format::eR8Uscaled: return BlockParams{1, 1, 1};
115  case vk::Format::eR8Sscaled: return BlockParams{1, 1, 1};
116  case vk::Format::eR8Uint: return BlockParams{1, 1, 1};
117  case vk::Format::eR8Sint: return BlockParams{1, 1, 1};
118  case vk::Format::eR8Srgb: return BlockParams{1, 1, 1};
119  case vk::Format::eR8G8Unorm: return BlockParams{1, 1, 2};
120  case vk::Format::eR8G8Snorm: return BlockParams{1, 1, 2};
121  case vk::Format::eR8G8Uscaled: return BlockParams{1, 1, 2};
122  case vk::Format::eR8G8Sscaled: return BlockParams{1, 1, 2};
123  case vk::Format::eR8G8Uint: return BlockParams{1, 1, 2};
124  case vk::Format::eR8G8Sint: return BlockParams{1, 1, 2};
125  case vk::Format::eR8G8Srgb: return BlockParams{1, 1, 2};
126  case vk::Format::eR8G8B8Unorm: return BlockParams{1, 1, 3};
127  case vk::Format::eR8G8B8Snorm: return BlockParams{1, 1, 3};
128  case vk::Format::eR8G8B8Uscaled: return BlockParams{1, 1, 3};
129  case vk::Format::eR8G8B8Sscaled: return BlockParams{1, 1, 3};
130  case vk::Format::eR8G8B8Uint: return BlockParams{1, 1, 3};
131  case vk::Format::eR8G8B8Sint: return BlockParams{1, 1, 3};
132  case vk::Format::eR8G8B8Srgb: return BlockParams{1, 1, 3};
133  case vk::Format::eB8G8R8Unorm: return BlockParams{1, 1, 3};
134  case vk::Format::eB8G8R8Snorm: return BlockParams{1, 1, 3};
135  case vk::Format::eB8G8R8Uscaled: return BlockParams{1, 1, 3};
136  case vk::Format::eB8G8R8Sscaled: return BlockParams{1, 1, 3};
137  case vk::Format::eB8G8R8Uint: return BlockParams{1, 1, 3};
138  case vk::Format::eB8G8R8Sint: return BlockParams{1, 1, 3};
139  case vk::Format::eB8G8R8Srgb: return BlockParams{1, 1, 3};
140  case vk::Format::eR8G8B8A8Unorm: return BlockParams{1, 1, 4};
141  case vk::Format::eR8G8B8A8Snorm: return BlockParams{1, 1, 4};
142  case vk::Format::eR8G8B8A8Uscaled: return BlockParams{1, 1, 4};
143  case vk::Format::eR8G8B8A8Sscaled: return BlockParams{1, 1, 4};
144  case vk::Format::eR8G8B8A8Uint: return BlockParams{1, 1, 4};
145  case vk::Format::eR8G8B8A8Sint: return BlockParams{1, 1, 4};
146  case vk::Format::eR8G8B8A8Srgb: return BlockParams{1, 1, 4};
147  case vk::Format::eB8G8R8A8Unorm: return BlockParams{1, 1, 4};
148  case vk::Format::eB8G8R8A8Snorm: return BlockParams{1, 1, 4};
149  case vk::Format::eB8G8R8A8Uscaled: return BlockParams{1, 1, 4};
150  case vk::Format::eB8G8R8A8Sscaled: return BlockParams{1, 1, 4};
151  case vk::Format::eB8G8R8A8Uint: return BlockParams{1, 1, 4};
152  case vk::Format::eB8G8R8A8Sint: return BlockParams{1, 1, 4};
153  case vk::Format::eB8G8R8A8Srgb: return BlockParams{1, 1, 4};
154  case vk::Format::eA8B8G8R8UnormPack32: return BlockParams{1, 1, 4};
155  case vk::Format::eA8B8G8R8SnormPack32: return BlockParams{1, 1, 4};
156  case vk::Format::eA8B8G8R8UscaledPack32: return BlockParams{1, 1, 4};
157  case vk::Format::eA8B8G8R8SscaledPack32: return BlockParams{1, 1, 4};
158  case vk::Format::eA8B8G8R8UintPack32: return BlockParams{1, 1, 4};
159  case vk::Format::eA8B8G8R8SintPack32: return BlockParams{1, 1, 4};
160  case vk::Format::eA8B8G8R8SrgbPack32: return BlockParams{1, 1, 4};
161  case vk::Format::eA2R10G10B10UnormPack32: return BlockParams{1, 1, 4};
162  case vk::Format::eA2R10G10B10SnormPack32: return BlockParams{1, 1, 4};
163  case vk::Format::eA2R10G10B10UscaledPack32: return BlockParams{1, 1, 4};
164  case vk::Format::eA2R10G10B10SscaledPack32: return BlockParams{1, 1, 4};
165  case vk::Format::eA2R10G10B10UintPack32: return BlockParams{1, 1, 4};
166  case vk::Format::eA2R10G10B10SintPack32: return BlockParams{1, 1, 4};
167  case vk::Format::eA2B10G10R10UnormPack32: return BlockParams{1, 1, 4};
168  case vk::Format::eA2B10G10R10SnormPack32: return BlockParams{1, 1, 4};
169  case vk::Format::eA2B10G10R10UscaledPack32: return BlockParams{1, 1, 4};
170  case vk::Format::eA2B10G10R10SscaledPack32: return BlockParams{1, 1, 4};
171  case vk::Format::eA2B10G10R10UintPack32: return BlockParams{1, 1, 4};
172  case vk::Format::eA2B10G10R10SintPack32: return BlockParams{1, 1, 4};
173  case vk::Format::eR16Unorm: return BlockParams{1, 1, 2};
174  case vk::Format::eR16Snorm: return BlockParams{1, 1, 2};
175  case vk::Format::eR16Uscaled: return BlockParams{1, 1, 2};
176  case vk::Format::eR16Sscaled: return BlockParams{1, 1, 2};
177  case vk::Format::eR16Uint: return BlockParams{1, 1, 2};
178  case vk::Format::eR16Sint: return BlockParams{1, 1, 2};
179  case vk::Format::eR16Sfloat: return BlockParams{1, 1, 2};
180  case vk::Format::eR16G16Unorm: return BlockParams{1, 1, 4};
181  case vk::Format::eR16G16Snorm: return BlockParams{1, 1, 4};
182  case vk::Format::eR16G16Uscaled: return BlockParams{1, 1, 4};
183  case vk::Format::eR16G16Sscaled: return BlockParams{1, 1, 4};
184  case vk::Format::eR16G16Uint: return BlockParams{1, 1, 4};
185  case vk::Format::eR16G16Sint: return BlockParams{1, 1, 4};
186  case vk::Format::eR16G16Sfloat: return BlockParams{1, 1, 4};
187  case vk::Format::eR16G16B16Unorm: return BlockParams{1, 1, 6};
188  case vk::Format::eR16G16B16Snorm: return BlockParams{1, 1, 6};
189  case vk::Format::eR16G16B16Uscaled: return BlockParams{1, 1, 6};
190  case vk::Format::eR16G16B16Sscaled: return BlockParams{1, 1, 6};
191  case vk::Format::eR16G16B16Uint: return BlockParams{1, 1, 6};
192  case vk::Format::eR16G16B16Sint: return BlockParams{1, 1, 6};
193  case vk::Format::eR16G16B16Sfloat: return BlockParams{1, 1, 6};
194  case vk::Format::eR16G16B16A16Unorm: return BlockParams{1, 1, 8};
195  case vk::Format::eR16G16B16A16Snorm: return BlockParams{1, 1, 8};
196  case vk::Format::eR16G16B16A16Uscaled: return BlockParams{1, 1, 8};
197  case vk::Format::eR16G16B16A16Sscaled: return BlockParams{1, 1, 8};
198  case vk::Format::eR16G16B16A16Uint: return BlockParams{1, 1, 8};
199  case vk::Format::eR16G16B16A16Sint: return BlockParams{1, 1, 8};
200  case vk::Format::eR16G16B16A16Sfloat: return BlockParams{1, 1, 8};
201  case vk::Format::eR32Uint: return BlockParams{1, 1, 4};
202  case vk::Format::eR32Sint: return BlockParams{1, 1, 4};
203  case vk::Format::eR32Sfloat: return BlockParams{1, 1, 4};
204  case vk::Format::eR32G32Uint: return BlockParams{1, 1, 8};
205  case vk::Format::eR32G32Sint: return BlockParams{1, 1, 8};
206  case vk::Format::eR32G32Sfloat: return BlockParams{1, 1, 8};
207  case vk::Format::eR32G32B32Uint: return BlockParams{1, 1, 12};
208  case vk::Format::eR32G32B32Sint: return BlockParams{1, 1, 12};
209  case vk::Format::eR32G32B32Sfloat: return BlockParams{1, 1, 12};
210  case vk::Format::eR32G32B32A32Uint: return BlockParams{1, 1, 16};
211  case vk::Format::eR32G32B32A32Sint: return BlockParams{1, 1, 16};
212  case vk::Format::eR32G32B32A32Sfloat: return BlockParams{1, 1, 16};
213  case vk::Format::eR64Uint: return BlockParams{1, 1, 8};
214  case vk::Format::eR64Sint: return BlockParams{1, 1, 8};
215  case vk::Format::eR64Sfloat: return BlockParams{1, 1, 8};
216  case vk::Format::eR64G64Uint: return BlockParams{1, 1, 16};
217  case vk::Format::eR64G64Sint: return BlockParams{1, 1, 16};
218  case vk::Format::eR64G64Sfloat: return BlockParams{1, 1, 16};
219  case vk::Format::eR64G64B64Uint: return BlockParams{1, 1, 24};
220  case vk::Format::eR64G64B64Sint: return BlockParams{1, 1, 24};
221  case vk::Format::eR64G64B64Sfloat: return BlockParams{1, 1, 24};
222  case vk::Format::eR64G64B64A64Uint: return BlockParams{1, 1, 32};
223  case vk::Format::eR64G64B64A64Sint: return BlockParams{1, 1, 32};
224  case vk::Format::eR64G64B64A64Sfloat: return BlockParams{1, 1, 32};
225  case vk::Format::eB10G11R11UfloatPack32: return BlockParams{1, 1, 4};
226  case vk::Format::eE5B9G9R9UfloatPack32: return BlockParams{1, 1, 4};
227  case vk::Format::eD16Unorm: return BlockParams{1, 1, 4};
228  case vk::Format::eX8D24UnormPack32: return BlockParams{1, 1, 4};
229  case vk::Format::eD32Sfloat: return BlockParams{1, 1, 4};
230  case vk::Format::eS8Uint: return BlockParams{1, 1, 1};
231  case vk::Format::eD16UnormS8Uint: return BlockParams{1, 1, 3};
232  case vk::Format::eD24UnormS8Uint: return BlockParams{1, 1, 4};
233  case vk::Format::eD32SfloatS8Uint: return BlockParams{0, 0, 0};
234  case vk::Format::eBc1RgbUnormBlock: return BlockParams{4, 4, 8};
235  case vk::Format::eBc1RgbSrgbBlock: return BlockParams{4, 4, 8};
236  case vk::Format::eBc1RgbaUnormBlock: return BlockParams{4, 4, 8};
237  case vk::Format::eBc1RgbaSrgbBlock: return BlockParams{4, 4, 8};
238  case vk::Format::eBc2UnormBlock: return BlockParams{4, 4, 16};
239  case vk::Format::eBc2SrgbBlock: return BlockParams{4, 4, 16};
240  case vk::Format::eBc3UnormBlock: return BlockParams{4, 4, 16};
241  case vk::Format::eBc3SrgbBlock: return BlockParams{4, 4, 16};
242  case vk::Format::eBc4UnormBlock: return BlockParams{4, 4, 16};
243  case vk::Format::eBc4SnormBlock: return BlockParams{4, 4, 16};
244  case vk::Format::eBc5UnormBlock: return BlockParams{4, 4, 16};
245  case vk::Format::eBc5SnormBlock: return BlockParams{4, 4, 16};
246  case vk::Format::eBc6HUfloatBlock: return BlockParams{0, 0, 0};
247  case vk::Format::eBc6HSfloatBlock: return BlockParams{0, 0, 0};
248  case vk::Format::eBc7UnormBlock: return BlockParams{0, 0, 0};
249  case vk::Format::eBc7SrgbBlock: return BlockParams{0, 0, 0};
250  case vk::Format::eEtc2R8G8B8UnormBlock: return BlockParams{0, 0, 0};
251  case vk::Format::eEtc2R8G8B8SrgbBlock: return BlockParams{0, 0, 0};
252  case vk::Format::eEtc2R8G8B8A1UnormBlock: return BlockParams{0, 0, 0};
253  case vk::Format::eEtc2R8G8B8A1SrgbBlock: return BlockParams{0, 0, 0};
254  case vk::Format::eEtc2R8G8B8A8UnormBlock: return BlockParams{0, 0, 0};
255  case vk::Format::eEtc2R8G8B8A8SrgbBlock: return BlockParams{0, 0, 0};
256  case vk::Format::eEacR11UnormBlock: return BlockParams{0, 0, 0};
257  case vk::Format::eEacR11SnormBlock: return BlockParams{0, 0, 0};
258  case vk::Format::eEacR11G11UnormBlock: return BlockParams{0, 0, 0};
259  case vk::Format::eEacR11G11SnormBlock: return BlockParams{0, 0, 0};
260  case vk::Format::eAstc4x4UnormBlock: return BlockParams{0, 0, 0};
261  case vk::Format::eAstc4x4SrgbBlock: return BlockParams{0, 0, 0};
262  case vk::Format::eAstc5x4UnormBlock: return BlockParams{0, 0, 0};
263  case vk::Format::eAstc5x4SrgbBlock: return BlockParams{0, 0, 0};
264  case vk::Format::eAstc5x5UnormBlock: return BlockParams{0, 0, 0};
265  case vk::Format::eAstc5x5SrgbBlock: return BlockParams{0, 0, 0};
266  case vk::Format::eAstc6x5UnormBlock: return BlockParams{0, 0, 0};
267  case vk::Format::eAstc6x5SrgbBlock: return BlockParams{0, 0, 0};
268  case vk::Format::eAstc6x6UnormBlock: return BlockParams{0, 0, 0};
269  case vk::Format::eAstc6x6SrgbBlock: return BlockParams{0, 0, 0};
270  case vk::Format::eAstc8x5UnormBlock: return BlockParams{0, 0, 0};
271  case vk::Format::eAstc8x5SrgbBlock: return BlockParams{0, 0, 0};
272  case vk::Format::eAstc8x6UnormBlock: return BlockParams{0, 0, 0};
273  case vk::Format::eAstc8x6SrgbBlock: return BlockParams{0, 0, 0};
274  case vk::Format::eAstc8x8UnormBlock: return BlockParams{0, 0, 0};
275  case vk::Format::eAstc8x8SrgbBlock: return BlockParams{0, 0, 0};
276  case vk::Format::eAstc10x5UnormBlock: return BlockParams{0, 0, 0};
277  case vk::Format::eAstc10x5SrgbBlock: return BlockParams{0, 0, 0};
278  case vk::Format::eAstc10x6UnormBlock: return BlockParams{0, 0, 0};
279  case vk::Format::eAstc10x6SrgbBlock: return BlockParams{0, 0, 0};
280  case vk::Format::eAstc10x8UnormBlock: return BlockParams{0, 0, 0};
281  case vk::Format::eAstc10x8SrgbBlock: return BlockParams{0, 0, 0};
282  case vk::Format::eAstc10x10UnormBlock: return BlockParams{0, 0, 0};
283  case vk::Format::eAstc10x10SrgbBlock: return BlockParams{0, 0, 0};
284  case vk::Format::eAstc12x10UnormBlock: return BlockParams{0, 0, 0};
285  case vk::Format::eAstc12x10SrgbBlock: return BlockParams{0, 0, 0};
286  case vk::Format::eAstc12x12UnormBlock: return BlockParams{0, 0, 0};
287  case vk::Format::eAstc12x12SrgbBlock: return BlockParams{0, 0, 0};
288  case vk::Format::ePvrtc12BppUnormBlockIMG: return BlockParams{0, 0, 0};
289  case vk::Format::ePvrtc14BppUnormBlockIMG: return BlockParams{0, 0, 0};
290  case vk::Format::ePvrtc22BppUnormBlockIMG: return BlockParams{0, 0, 0};
291  case vk::Format::ePvrtc24BppUnormBlockIMG: return BlockParams{0, 0, 0};
292  case vk::Format::ePvrtc12BppSrgbBlockIMG: return BlockParams{0, 0, 0};
293  case vk::Format::ePvrtc14BppSrgbBlockIMG: return BlockParams{0, 0, 0};
294  case vk::Format::ePvrtc22BppSrgbBlockIMG: return BlockParams{0, 0, 0};
295  case vk::Format::ePvrtc24BppSrgbBlockIMG: return BlockParams{0, 0, 0};
296  }
297  return BlockParams{0, 0, 0};
298 }
299 
310 public:
311  RenderpassMaker() {
312  }
313 
316  void attachmentBegin(vk::Format format) {
317  vk::AttachmentDescription desc{{}, format};
318  s.attachmentDescriptions.push_back(desc);
319  }
320 
321  void attachmentFlags(vk::AttachmentDescriptionFlags value) { s.attachmentDescriptions.back().flags = value; };
322  void attachmentFormat(vk::Format value) { s.attachmentDescriptions.back().format = value; };
323  void attachmentSamples(vk::SampleCountFlagBits value) { s.attachmentDescriptions.back().samples = value; };
324  void attachmentLoadOp(vk::AttachmentLoadOp value) { s.attachmentDescriptions.back().loadOp = value; };
325  void attachmentStoreOp(vk::AttachmentStoreOp value) { s.attachmentDescriptions.back().storeOp = value; };
326  void attachmentStencilLoadOp(vk::AttachmentLoadOp value) { s.attachmentDescriptions.back().stencilLoadOp = value; };
327  void attachmentStencilStoreOp(vk::AttachmentStoreOp value) { s.attachmentDescriptions.back().stencilStoreOp = value; };
328  void attachmentInitialLayout(vk::ImageLayout value) { s.attachmentDescriptions.back().initialLayout = value; };
329  void attachmentFinalLayout(vk::ImageLayout value) { s.attachmentDescriptions.back().finalLayout = value; };
330 
334  void subpassBegin(vk::PipelineBindPoint bp) {
335  vk::SubpassDescription desc{};
336  desc.pipelineBindPoint = bp;
337  s.subpassDescriptions.push_back(desc);
338  }
339 
340  void subpassColorAttachment(vk::ImageLayout layout, uint32_t attachment) {
341  vk::SubpassDescription &subpass = s.subpassDescriptions.back();
342  auto *p = getAttachmentReference();
343  p->layout = layout;
344  p->attachment = attachment;
345  if (subpass.colorAttachmentCount == 0) {
346  subpass.pColorAttachments = p;
347  }
348  subpass.colorAttachmentCount++;
349  }
350 
351  void subpassDepthStencilAttachment(vk::ImageLayout layout, uint32_t attachment) {
352  vk::SubpassDescription &subpass = s.subpassDescriptions.back();
353  auto *p = getAttachmentReference();
354  p->layout = layout;
355  p->attachment = attachment;
356  subpass.pDepthStencilAttachment = p;
357  }
358 
359  vk::UniqueRenderPass createUnique(const vk::Device &device) const {
360  vk::RenderPassCreateInfo renderPassInfo{};
361  renderPassInfo.attachmentCount = (uint32_t)s.attachmentDescriptions.size();
362  renderPassInfo.pAttachments = s.attachmentDescriptions.data();
363  renderPassInfo.subpassCount = (uint32_t)s.subpassDescriptions.size();
364  renderPassInfo.pSubpasses = s.subpassDescriptions.data();
365  renderPassInfo.dependencyCount = (uint32_t)s.subpassDependencies.size();
366  renderPassInfo.pDependencies = s.subpassDependencies.data();
367  return device.createRenderPassUnique(renderPassInfo);
368  }
369 
370  void dependencyBegin(uint32_t srcSubpass, uint32_t dstSubpass) {
371  vk::SubpassDependency desc{};
372  desc.srcSubpass = srcSubpass;
373  desc.dstSubpass = dstSubpass;
374  s.subpassDependencies.push_back(desc);
375  }
376 
377  void dependencySrcSubpass(uint32_t value) { s.subpassDependencies.back().srcSubpass = value; };
378  void dependencyDstSubpass(uint32_t value) { s.subpassDependencies.back().dstSubpass = value; };
379  void dependencySrcStageMask(vk::PipelineStageFlags value) { s.subpassDependencies.back().srcStageMask = value; };
380  void dependencyDstStageMask(vk::PipelineStageFlags value) { s.subpassDependencies.back().dstStageMask = value; };
381  void dependencySrcAccessMask(vk::AccessFlags value) { s.subpassDependencies.back().srcAccessMask = value; };
382  void dependencyDstAccessMask(vk::AccessFlags value) { s.subpassDependencies.back().dstAccessMask = value; };
383  void dependencyDependencyFlags(vk::DependencyFlags value) { s.subpassDependencies.back().dependencyFlags = value; };
384 private:
385  constexpr static int max_refs = 64;
386 
387  vk::AttachmentReference *getAttachmentReference() {
388  return (s.num_refs < max_refs) ? &s.attachmentReferences[s.num_refs++] : nullptr;
389  }
390 
391  struct State {
392  std::vector<vk::AttachmentDescription> attachmentDescriptions;
393  std::vector<vk::SubpassDescription> subpassDescriptions;
394  std::vector<vk::SubpassDependency> subpassDependencies;
395  std::array<vk::AttachmentReference, max_refs> attachmentReferences;
396  int num_refs = 0;
397  bool ok_ = false;
398  };
399 
400  State s;
401 };
402 
405 public:
406  ShaderModule() {
407  }
408 
410  ShaderModule(const vk::Device &device, const std::string &filename) {
411  auto file = std::ifstream(filename, std::ios::binary);
412  if (file.bad()) {
413  return;
414  }
415 
416  file.seekg(0, std::ios::end);
417  int length = (int)file.tellg();
418 
419  s.opcodes_.resize((size_t)(length / 4));
420  file.seekg(0, std::ios::beg);
421  file.read((char *)s.opcodes_.data(), s.opcodes_.size() * 4);
422 
423  vk::ShaderModuleCreateInfo ci;
424  ci.codeSize = s.opcodes_.size() * 4;
425  ci.pCode = s.opcodes_.data();
426  s.module_ = device.createShaderModuleUnique(ci);
427 
428  s.ok_ = true;
429  }
430 
432  template<class InIter>
433  ShaderModule(const vk::Device &device, InIter begin, InIter end) {
434  s.opcodes_.assign(begin, end);
435  vk::ShaderModuleCreateInfo ci;
436  ci.codeSize = s.opcodes_.size() * 4;
437  ci.pCode = s.opcodes_.data();
438  s.module_ = device.createShaderModuleUnique(ci);
439 
440  s.ok_ = true;
441  }
442 
444  struct Variable {
445  // The name of the variable from the GLSL/HLSL
446  std::string debugName;
447 
448  // The internal name (integer) of the variable
449  int name;
450 
451  // The location in the binding.
452  int location;
453 
454  // The binding in the descriptor set or I/O channel.
455  int binding;
456 
457  // The descriptor set (for uniforms)
458  int set;
459  int instruction;
460 
461  // Storage class of the variable, eg. spv::StorageClass::Uniform
462  spv::StorageClass storageClass;
463  };
464 
469  std::vector<Variable> getVariables() const {
470  auto bound = s.opcodes_[3];
471 
472  std::unordered_map<int, int> bindings;
473  std::unordered_map<int, int> locations;
474  std::unordered_map<int, int> sets;
475  std::unordered_map<int, std::string> debugNames;
476 
477  for (int i = 5; i != s.opcodes_.size(); i += s.opcodes_[i] >> 16) {
478  spv::Op op = spv::Op(s.opcodes_[i] & 0xffff);
479  if (op == spv::Op::OpDecorate) {
480  int name = s.opcodes_[i + 1];
481  auto decoration = spv::Decoration(s.opcodes_[i + 2]);
482  if (decoration == spv::Decoration::Binding) {
483  bindings[name] = s.opcodes_[i + 3];
484  } else if (decoration == spv::Decoration::Location) {
485  locations[name] = s.opcodes_[i + 3];
486  } else if (decoration == spv::Decoration::DescriptorSet) {
487  sets[name] = s.opcodes_[i + 3];
488  }
489  } else if (op == spv::Op::OpName) {
490  int name = s.opcodes_[i + 1];
491  debugNames[name] = (const char *)&s.opcodes_[i + 2];
492  }
493  }
494 
495  std::vector<Variable> result;
496  for (int i = 5; i != s.opcodes_.size(); i += s.opcodes_[i] >> 16) {
497  spv::Op op = spv::Op(s.opcodes_[i] & 0xffff);
498  if (op == spv::Op::OpVariable) {
499  int name = s.opcodes_[i + 1];
500  auto sc = spv::StorageClass(s.opcodes_[i + 3]);
501  Variable b;
502  b.debugName = debugNames[name];
503  b.name = name;
504  b.location = locations[name];
505  b.set = sets[name];
506  b.instruction = i;
507  b.storageClass = sc;
508  result.push_back(b);
509  }
510  }
511  return std::move(result);
512  }
513 
514  bool ok() const { return s.ok_; }
515  VkShaderModule module() { return *s.module_; }
516 
519  std::ostream &write(std::ostream &os) {
520  os << "static const uint32_t shader[] = {\n";
521  char tmp[256];
522  auto p = s.opcodes_.begin();
523  snprintf(
524  tmp, sizeof(tmp), " 0x%08x,0x%08x,0x%08x,0x%08x,0x%08x,\n", p[0], p[1], p[2], p[3], p[4]);
525  os << tmp;
526  for (int i = 5; i != s.opcodes_.size(); i += s.opcodes_[i] >> 16) {
527  char *p = tmp + 2, *e = tmp + sizeof(tmp) - 2;
528  for (int j = i; j != i + (s.opcodes_[i] >> 16); ++j) {
529  p += snprintf(p, e-p, "0x%08x,", s.opcodes_[j]);
530  if (p > e-16) { *p++ = '\n'; *p = 0; os << tmp; p = tmp + 2; }
531  }
532  *p++ = '\n';
533  *p = 0;
534  os << tmp;
535  }
536  os << "};\n\n";
537  return os;
538  }
539 
540 private:
541  struct State {
542  std::vector<uint32_t> opcodes_;
543  vk::UniqueShaderModule module_;
544  bool ok_;
545  };
546 
547  State s;
548 };
549 
553 public:
555 
557  vk::UniquePipelineLayout createUnique(const vk::Device &device) const {
558  vk::PipelineLayoutCreateInfo pipelineLayoutInfo{
559  {}, (uint32_t)setLayouts_.size(),
560  setLayouts_.data(), (uint32_t)pushConstantRanges_.size(),
561  pushConstantRanges_.data()};
562  return std::move(device.createPipelineLayoutUnique(pipelineLayoutInfo));
563  }
564 
566  void descriptorSetLayout(vk::DescriptorSetLayout layout) {
567  setLayouts_.push_back(layout);
568  }
569 
572  void pushConstantRange(vk::ShaderStageFlags stageFlags_, uint32_t offset_, uint32_t size_) {
573  pushConstantRanges_.emplace_back(stageFlags_, offset_, size_);
574  }
575 
576 private:
577  std::vector<vk::DescriptorSetLayout> setLayouts_;
578  std::vector<vk::PushConstantRange> pushConstantRanges_;
579 };
580 
588 public:
589  PipelineMaker(uint32_t width, uint32_t height) {
590  inputAssemblyState_.topology = vk::PrimitiveTopology::eTriangleList;
591  viewport_ = vk::Viewport{0.0f, 0.0f, (float)width, (float)height, 0.0f, 1.0f};
592  scissor_ = vk::Rect2D{{0, 0}, {width, height}};
593  rasterizationState_.lineWidth = 1.0f;
594 
595  // Set up depth test, but do not enable it.
596  depthStencilState_.depthTestEnable = VK_FALSE;
597  depthStencilState_.depthWriteEnable = VK_TRUE;
598  depthStencilState_.depthCompareOp = vk::CompareOp::eLessOrEqual;
599  depthStencilState_.depthBoundsTestEnable = VK_FALSE;
600  depthStencilState_.back.failOp = vk::StencilOp::eKeep;
601  depthStencilState_.back.passOp = vk::StencilOp::eKeep;
602  depthStencilState_.back.compareOp = vk::CompareOp::eAlways;
603  depthStencilState_.stencilTestEnable = VK_FALSE;
604  depthStencilState_.front = depthStencilState_.back;
605  }
606 
607  vk::UniquePipeline createUnique(const vk::Device &device,
608  const vk::PipelineCache &pipelineCache,
609  const vk::PipelineLayout &pipelineLayout,
610  const vk::RenderPass &renderPass, bool defaultBlend=true) {
611 
612  // Add default colour blend attachment if necessary.
613  if (colorBlendAttachments_.empty() && defaultBlend) {
614  vk::PipelineColorBlendAttachmentState blend{};
615  blend.blendEnable = 0;
616  blend.srcColorBlendFactor = vk::BlendFactor::eOne;
617  blend.dstColorBlendFactor = vk::BlendFactor::eZero;
618  blend.colorBlendOp = vk::BlendOp::eAdd;
619  blend.srcAlphaBlendFactor = vk::BlendFactor::eOne;
620  blend.dstAlphaBlendFactor = vk::BlendFactor::eZero;
621  blend.alphaBlendOp = vk::BlendOp::eAdd;
622  typedef vk::ColorComponentFlagBits ccbf;
623  blend.colorWriteMask = ccbf::eR|ccbf::eG|ccbf::eB|ccbf::eA;
624  colorBlendAttachments_.push_back(blend);
625  }
626 
627  auto count = (uint32_t)colorBlendAttachments_.size();
628  colorBlendState_.attachmentCount = count;
629  colorBlendState_.pAttachments = count ? colorBlendAttachments_.data() : nullptr;
630 
631  vk::PipelineViewportStateCreateInfo viewportState{
632  {}, 1, &viewport_, 1, &scissor_};
633 
634  vk::PipelineVertexInputStateCreateInfo vertexInputState;
635  vertexInputState.vertexAttributeDescriptionCount = (uint32_t)vertexAttributeDescriptions_.size();
636  vertexInputState.pVertexAttributeDescriptions = vertexAttributeDescriptions_.data();
637  vertexInputState.vertexBindingDescriptionCount = (uint32_t)vertexBindingDescriptions_.size();
638  vertexInputState.pVertexBindingDescriptions = vertexBindingDescriptions_.data();
639 
640  vk::PipelineDynamicStateCreateInfo dynState{{}, (uint32_t)dynamicState_.size(), dynamicState_.data()};
641 
642  vk::GraphicsPipelineCreateInfo pipelineInfo{};
643  pipelineInfo.pVertexInputState = &vertexInputState;
644  pipelineInfo.stageCount = (uint32_t)modules_.size();
645  pipelineInfo.pStages = modules_.data();
646  pipelineInfo.pInputAssemblyState = &inputAssemblyState_;
647  pipelineInfo.pViewportState = &viewportState;
648  pipelineInfo.pRasterizationState = &rasterizationState_;
649  pipelineInfo.pMultisampleState = &multisampleState_;
650  pipelineInfo.pColorBlendState = &colorBlendState_;
651  pipelineInfo.pDepthStencilState = &depthStencilState_;
652  pipelineInfo.layout = pipelineLayout;
653  pipelineInfo.renderPass = renderPass;
654  pipelineInfo.pDynamicState = dynamicState_.empty() ? nullptr : &dynState;
655  pipelineInfo.subpass = subpass_;
656 
657  return device.createGraphicsPipelineUnique(pipelineCache, pipelineInfo);
658  }
659 
661  void shader(vk::ShaderStageFlagBits stage, vku::ShaderModule &shader,
662  const char *entryPoint = "main") {
663  vk::PipelineShaderStageCreateInfo info{};
664  info.module = shader.module();
665  info.pName = entryPoint;
666  info.stage = stage;
667  modules_.emplace_back(info);
668  }
669 
672  void colorBlend(const vk::PipelineColorBlendAttachmentState &state) {
673  colorBlendAttachments_.push_back(state);
674  }
675 
676  void subPass(uint32_t subpass) {
677  subpass_ = subpass;
678  }
679 
684  void blendBegin(vk::Bool32 enable) {
685  colorBlendAttachments_.emplace_back();
686  auto &blend = colorBlendAttachments_.back();
687  blend.blendEnable = enable;
688  blend.srcColorBlendFactor = vk::BlendFactor::eSrcAlpha;
689  blend.dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha;
690  blend.colorBlendOp = vk::BlendOp::eAdd;
691  blend.srcAlphaBlendFactor = vk::BlendFactor::eSrcAlpha;
692  blend.dstAlphaBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha;
693  blend.alphaBlendOp = vk::BlendOp::eAdd;
694  typedef vk::ColorComponentFlagBits ccbf;
695  blend.colorWriteMask = ccbf::eR|ccbf::eG|ccbf::eB|ccbf::eA;
696  }
697 
699  void blendEnable(vk::Bool32 value) { colorBlendAttachments_.back().blendEnable = value; }
700 
702  void blendSrcColorBlendFactor(vk::BlendFactor value) { colorBlendAttachments_.back().srcColorBlendFactor = value; }
703 
705  void blendDstColorBlendFactor(vk::BlendFactor value) { colorBlendAttachments_.back().dstColorBlendFactor = value; }
706 
708  void blendColorBlendOp(vk::BlendOp value) { colorBlendAttachments_.back().colorBlendOp = value; }
709 
711  void blendSrcAlphaBlendFactor(vk::BlendFactor value) { colorBlendAttachments_.back().srcAlphaBlendFactor = value; }
712 
714  void blendDstAlphaBlendFactor(vk::BlendFactor value) { colorBlendAttachments_.back().dstAlphaBlendFactor = value; }
715 
717  void blendAlphaBlendOp(vk::BlendOp value) { colorBlendAttachments_.back().alphaBlendOp = value; }
718 
720  void blendColorWriteMask(vk::ColorComponentFlags value) { colorBlendAttachments_.back().colorWriteMask = value; }
721 
723  void vertexAttribute(uint32_t location_, uint32_t binding_, vk::Format format_, uint32_t offset_) {
724  vertexAttributeDescriptions_.push_back({location_, binding_, format_, offset_});
725  }
726 
728  void vertexAttribute(const vk::VertexInputAttributeDescription &desc) {
729  vertexAttributeDescriptions_.push_back(desc);
730  }
731 
735  void vertexBinding(uint32_t binding_, uint32_t stride_, vk::VertexInputRate inputRate_ = vk::VertexInputRate::eVertex) {
736  vertexBindingDescriptions_.push_back({binding_, stride_, inputRate_});
737  }
738 
742  void vertexBinding(const vk::VertexInputBindingDescription &desc) {
743  vertexBindingDescriptions_.push_back(desc);
744  }
745 
748  PipelineMaker &topology( vk::PrimitiveTopology topology ) { inputAssemblyState_.topology = topology; return *this; }
749 
752  PipelineMaker &primitiveRestartEnable( vk::Bool32 primitiveRestartEnable ) { inputAssemblyState_.primitiveRestartEnable = primitiveRestartEnable; return *this; }
753 
756  PipelineMaker &inputAssemblyState(const vk::PipelineInputAssemblyStateCreateInfo &value) { inputAssemblyState_ = value; return *this; }
757 
760  PipelineMaker &viewport(const vk::Viewport &value) { viewport_ = value; return *this; }
761 
764  PipelineMaker &scissor(const vk::Rect2D &value) { scissor_ = value; return *this; }
765 
768  PipelineMaker &rasterizationState(const vk::PipelineRasterizationStateCreateInfo &value) { rasterizationState_ = value; return *this; }
769  PipelineMaker &depthClampEnable(vk::Bool32 value) { rasterizationState_.depthClampEnable = value; return *this; }
770  PipelineMaker &rasterizerDiscardEnable(vk::Bool32 value) { rasterizationState_.rasterizerDiscardEnable = value; return *this; }
771  PipelineMaker &polygonMode(vk::PolygonMode value) { rasterizationState_.polygonMode = value; return *this; }
772  PipelineMaker &cullMode(vk::CullModeFlags value) { rasterizationState_.cullMode = value; return *this; }
773  PipelineMaker &frontFace(vk::FrontFace value) { rasterizationState_.frontFace = value; return *this; }
774  PipelineMaker &depthBiasEnable(vk::Bool32 value) { rasterizationState_.depthBiasEnable = value; return *this; }
775  PipelineMaker &depthBiasConstantFactor(float value) { rasterizationState_.depthBiasConstantFactor = value; return *this; }
776  PipelineMaker &depthBiasClamp(float value) { rasterizationState_.depthBiasClamp = value; return *this; }
777  PipelineMaker &depthBiasSlopeFactor(float value) { rasterizationState_.depthBiasSlopeFactor = value; return *this; }
778  PipelineMaker &lineWidth(float value) { rasterizationState_.lineWidth = value; return *this; }
779 
780 
783  PipelineMaker &multisampleState(const vk::PipelineMultisampleStateCreateInfo &value) { multisampleState_ = value; return *this; }
784  PipelineMaker &rasterizationSamples(vk::SampleCountFlagBits value) { multisampleState_.rasterizationSamples = value; return *this; }
785  PipelineMaker &sampleShadingEnable(vk::Bool32 value) { multisampleState_.sampleShadingEnable = value; return *this; }
786  PipelineMaker &minSampleShading(float value) { multisampleState_.minSampleShading = value; return *this; }
787  PipelineMaker &pSampleMask(const vk::SampleMask* value) { multisampleState_.pSampleMask = value; return *this; }
788  PipelineMaker &alphaToCoverageEnable(vk::Bool32 value) { multisampleState_.alphaToCoverageEnable = value; return *this; }
789  PipelineMaker &alphaToOneEnable(vk::Bool32 value) { multisampleState_.alphaToOneEnable = value; return *this; }
790 
793  PipelineMaker &depthStencilState(const vk::PipelineDepthStencilStateCreateInfo &value) { depthStencilState_ = value; return *this; }
794  PipelineMaker &depthTestEnable(vk::Bool32 value) { depthStencilState_.depthTestEnable = value; return *this; }
795  PipelineMaker &depthWriteEnable(vk::Bool32 value) { depthStencilState_.depthWriteEnable = value; return *this; }
796  PipelineMaker &depthCompareOp(vk::CompareOp value) { depthStencilState_.depthCompareOp = value; return *this; }
797  PipelineMaker &depthBoundsTestEnable(vk::Bool32 value) { depthStencilState_.depthBoundsTestEnable = value; return *this; }
798  PipelineMaker &stencilTestEnable(vk::Bool32 value) { depthStencilState_.stencilTestEnable = value; return *this; }
799  PipelineMaker &front(vk::StencilOpState value) { depthStencilState_.front = value; return *this; }
800  PipelineMaker &back(vk::StencilOpState value) { depthStencilState_.back = value; return *this; }
801  PipelineMaker &minDepthBounds(float value) { depthStencilState_.minDepthBounds = value; return *this; }
802  PipelineMaker &maxDepthBounds(float value) { depthStencilState_.maxDepthBounds = value; return *this; }
803 
806  PipelineMaker &colorBlendState(const vk::PipelineColorBlendStateCreateInfo &value) { colorBlendState_ = value; return *this; }
807  PipelineMaker &logicOpEnable(vk::Bool32 value) { colorBlendState_.logicOpEnable = value; return *this; }
808  PipelineMaker &logicOp(vk::LogicOp value) { colorBlendState_.logicOp = value; return *this; }
809  PipelineMaker &blendConstants(float r, float g, float b, float a) { float *bc = colorBlendState_.blendConstants; bc[0] = r; bc[1] = g; bc[2] = b; bc[3] = a; return *this; }
810 
811  PipelineMaker &dynamicState(vk::DynamicState value) { dynamicState_.push_back(value); }
812 private:
813  vk::PipelineInputAssemblyStateCreateInfo inputAssemblyState_;
814  vk::Viewport viewport_;
815  vk::Rect2D scissor_;
816  vk::PipelineRasterizationStateCreateInfo rasterizationState_;
817  vk::PipelineMultisampleStateCreateInfo multisampleState_;
818  vk::PipelineDepthStencilStateCreateInfo depthStencilState_;
819  vk::PipelineColorBlendStateCreateInfo colorBlendState_;
820  std::vector<vk::PipelineColorBlendAttachmentState> colorBlendAttachments_;
821  std::vector<vk::PipelineShaderStageCreateInfo> modules_;
822  std::vector<vk::VertexInputAttributeDescription> vertexAttributeDescriptions_;
823  std::vector<vk::VertexInputBindingDescription> vertexBindingDescriptions_;
824  std::vector<vk::DynamicState> dynamicState_;
825  uint32_t subpass_ = 0;
826 };
827 
830 public:
832  }
833 
835  void shader(vk::ShaderStageFlagBits stage, vku::ShaderModule &shader,
836  const char *entryPoint = "main") {
837  stage_.module = shader.module();
838  stage_.pName = entryPoint;
839  stage_.stage = stage;
840  }
841 
843  ComputePipelineMaker &module(const vk::PipelineShaderStageCreateInfo &value) {
844  stage_ = value;
845  }
846 
848  vk::UniquePipeline createUnique(vk::Device device, const vk::PipelineCache &pipelineCache, const vk::PipelineLayout &pipelineLayout) {
849  vk::ComputePipelineCreateInfo pipelineInfo{};
850 
851  pipelineInfo.stage = stage_;
852  pipelineInfo.layout = pipelineLayout;
853 
854  return device.createComputePipelineUnique(pipelineCache, pipelineInfo);
855  }
856 private:
857  vk::PipelineShaderStageCreateInfo stage_;
858 };
859 
863 public:
864  GenericBuffer() {
865  }
866 
867  GenericBuffer(vk::Device device, vk::PhysicalDeviceMemoryProperties memprops, vk::BufferUsageFlags usage, vk::DeviceSize size, vk::MemoryPropertyFlags memflags = vk::MemoryPropertyFlagBits::eDeviceLocal) {
868  // Create the buffer object without memory.
869  vk::BufferCreateInfo ci{};
870  ci.size = size_ = size;
871  ci.usage = usage;
872  ci.sharingMode = vk::SharingMode::eExclusive;
873  buffer_ = device.createBufferUnique(ci);
874 
875  // Find out how much memory and which heap to allocate from.
876  auto memreq = device.getBufferMemoryRequirements(*buffer_);
877 
878  // Create a memory object to bind to the buffer.
879  vk::MemoryAllocateInfo mai{};
880  mai.allocationSize = memreq.size;
881  mai.memoryTypeIndex = vku::findMemoryTypeIndex(memprops, memreq.memoryTypeBits, memflags);
882  mem_ = device.allocateMemoryUnique(mai);
883 
884  device.bindBufferMemory(*buffer_, *mem_, 0);
885  }
886 
888  void updateLocal(const vk::Device &device, const void *value, vk::DeviceSize size) const {
889  void *ptr = device.mapMemory(*mem_, 0, size_, vk::MemoryMapFlags{});
890  memcpy(ptr, value, (size_t)size);
891  flush(device);
892  device.unmapMemory(*mem_);
893  }
894 
897  void upload(vk::Device device, const vk::PhysicalDeviceMemoryProperties &memprops, vk::CommandPool commandPool, vk::Queue queue, const void *value, vk::DeviceSize size) const {
898  if (size == 0) return;
899  using buf = vk::BufferUsageFlagBits;
900  using pfb = vk::MemoryPropertyFlagBits;
901  auto tmp = vku::GenericBuffer(device, memprops, buf::eTransferSrc, size, pfb::eHostVisible);
902  tmp.updateLocal(device, value, size);
903 
904  vku::executeImmediately(device, commandPool, queue, [&](vk::CommandBuffer cb) {
905  vk::BufferCopy bc{0, 0, size};
906  cb.copyBuffer(tmp.buffer(), *buffer_, bc);
907  });
908  }
909 
910  template<typename T>
911  void upload(vk::Device device, const vk::PhysicalDeviceMemoryProperties &memprops, vk::CommandPool commandPool, vk::Queue queue, const std::vector<T> &value) const {
912  upload(device, memprops, commandPool, queue, value.data(), value.size() * sizeof(T));
913  }
914 
915  template<typename T>
916  void upload(vk::Device device, const vk::PhysicalDeviceMemoryProperties &memprops, vk::CommandPool commandPool, vk::Queue queue, const T &value) const {
917  upload(device, memprops, commandPool, queue, &value, sizeof(value));
918  }
919 
920  void barrier(vk::CommandBuffer cb, vk::PipelineStageFlags srcStageMask, vk::PipelineStageFlags dstStageMask, vk::DependencyFlags dependencyFlags, vk::AccessFlags srcAccessMask, vk::AccessFlags dstAccessMask, uint32_t srcQueueFamilyIndex, uint32_t dstQueueFamilyIndex) const {
921  vk::BufferMemoryBarrier bmb{srcAccessMask, dstAccessMask, srcQueueFamilyIndex, dstQueueFamilyIndex, *buffer_, 0, size_};
922  cb.pipelineBarrier(srcStageMask, dstStageMask, dependencyFlags, nullptr, bmb, nullptr);
923  }
924 
925  template<class Type, class Allocator>
926  void updateLocal(const vk::Device &device, const std::vector<Type, Allocator> &value) const {
927  updateLocal(device, (void*)value.data(), vk::DeviceSize(value.size() * sizeof(Type)));
928  }
929 
930  template<class Type>
931  void updateLocal(const vk::Device &device, const Type &value) const {
932  updateLocal(device, (void*)&value, vk::DeviceSize(sizeof(Type)));
933  }
934 
935  void *map(const vk::Device &device) const { return device.mapMemory(*mem_, 0, size_, vk::MemoryMapFlags{}); };
936  void unmap(const vk::Device &device) const { return device.unmapMemory(*mem_); };
937 
938  void flush(const vk::Device &device) const {
939  vk::MappedMemoryRange mr{*mem_, 0, VK_WHOLE_SIZE};
940  return device.flushMappedMemoryRanges(mr);
941  }
942 
943  void invalidate(const vk::Device &device) const {
944  vk::MappedMemoryRange mr{*mem_, 0, VK_WHOLE_SIZE};
945  return device.invalidateMappedMemoryRanges(mr);
946  }
947 
948  vk::Buffer buffer() const { return *buffer_; }
949  vk::DeviceMemory mem() const { return *mem_; }
950  vk::DeviceSize size() const { return size_; }
951 private:
952  vk::UniqueBuffer buffer_;
953  vk::UniqueDeviceMemory mem_;
954  vk::DeviceSize size_;
955 };
956 
959 class VertexBuffer : public GenericBuffer {
960 public:
961  VertexBuffer() {
962  }
963 
964  VertexBuffer(const vk::Device &device, const vk::PhysicalDeviceMemoryProperties &memprops, size_t size) : GenericBuffer(device, memprops, vk::BufferUsageFlagBits::eVertexBuffer, size, vk::MemoryPropertyFlagBits::eDeviceLocal) {
965  }
966 };
967 
970 public:
971  HostVertexBuffer() {
972  }
973 
974  template<class Type, class Allocator>
975  HostVertexBuffer(const vk::Device &device, const vk::PhysicalDeviceMemoryProperties &memprops, const std::vector<Type, Allocator> &value) : GenericBuffer(device, memprops, vk::BufferUsageFlagBits::eVertexBuffer, value.size() * sizeof(Type), vk::MemoryPropertyFlagBits::eHostVisible) {
976  updateLocal(device, value);
977  }
978 };
979 
982 class IndexBuffer : public GenericBuffer {
983 public:
984  IndexBuffer() {
985  }
986 
987  IndexBuffer(const vk::Device &device, const vk::PhysicalDeviceMemoryProperties &memprops, vk::DeviceSize size) : GenericBuffer(device, memprops, vk::BufferUsageFlagBits::eIndexBuffer, size, vk::MemoryPropertyFlagBits::eDeviceLocal) {
988  }
989 };
990 
993 public:
994  HostIndexBuffer() {
995  }
996 
997  template<class Type, class Allocator>
998  HostIndexBuffer(const vk::Device &device, const vk::PhysicalDeviceMemoryProperties &memprops, const std::vector<Type, Allocator> &value) : GenericBuffer(device, memprops, vk::BufferUsageFlagBits::eIndexBuffer, value.size() * sizeof(Type), vk::MemoryPropertyFlagBits::eHostVisible) {
999  updateLocal(device, value);
1000  }
1001 };
1002 
1005 public:
1006  UniformBuffer() {
1007  }
1008 
1010  UniformBuffer(const vk::Device &device, const vk::PhysicalDeviceMemoryProperties &memprops, size_t size) : GenericBuffer(device, memprops, vk::BufferUsageFlagBits::eUniformBuffer|vk::BufferUsageFlagBits::eTransferDst, (vk::DeviceSize)size, vk::MemoryPropertyFlagBits::eDeviceLocal) {
1011  }
1012 };
1013 
1016 public:
1017  DescriptorSetUpdater(int maxBuffers = 10, int maxImages = 10, int maxBufferViews = 0) {
1018  // we must pre-size these buffers as we take pointers to their members.
1019  bufferInfo_.resize(maxBuffers);
1020  imageInfo_.resize(maxImages);
1021  bufferViews_.resize(maxBufferViews);
1022  }
1023 
1025  void beginDescriptorSet(vk::DescriptorSet dstSet) {
1026  dstSet_ = dstSet;
1027  }
1028 
1030  void beginImages(uint32_t dstBinding, uint32_t dstArrayElement, vk::DescriptorType descriptorType) {
1031  vk::WriteDescriptorSet wdesc{};
1032  wdesc.dstSet = dstSet_;
1033  wdesc.dstBinding = dstBinding;
1034  wdesc.dstArrayElement = dstArrayElement;
1035  wdesc.descriptorCount = 0;
1036  wdesc.descriptorType = descriptorType;
1037  wdesc.pImageInfo = imageInfo_.data() + numImages_;
1038  descriptorWrites_.push_back(wdesc);
1039  }
1040 
1042  void image(vk::Sampler sampler, vk::ImageView imageView, vk::ImageLayout imageLayout) {
1043  if (!descriptorWrites_.empty() && numImages_ != imageInfo_.size() && descriptorWrites_.back().pImageInfo) {
1044  descriptorWrites_.back().descriptorCount++;
1045  imageInfo_[numImages_++] = vk::DescriptorImageInfo{sampler, imageView, imageLayout};
1046  } else {
1047  ok_ = false;
1048  }
1049  }
1050 
1052  void beginBuffers(uint32_t dstBinding, uint32_t dstArrayElement, vk::DescriptorType descriptorType) {
1053  vk::WriteDescriptorSet wdesc{};
1054  wdesc.dstSet = dstSet_;
1055  wdesc.dstBinding = dstBinding;
1056  wdesc.dstArrayElement = dstArrayElement;
1057  wdesc.descriptorCount = 0;
1058  wdesc.descriptorType = descriptorType;
1059  wdesc.pBufferInfo = bufferInfo_.data() + numBuffers_;
1060  descriptorWrites_.push_back(wdesc);
1061  }
1062 
1064  void buffer(vk::Buffer buffer, vk::DeviceSize offset, vk::DeviceSize range) {
1065  if (!descriptorWrites_.empty() && numBuffers_ != bufferInfo_.size() && descriptorWrites_.back().pBufferInfo) {
1066  descriptorWrites_.back().descriptorCount++;
1067  bufferInfo_[numBuffers_++] = vk::DescriptorBufferInfo{buffer, offset, range};
1068  } else {
1069  ok_ = false;
1070  }
1071  }
1072 
1074  void beginBufferViews(uint32_t dstBinding, uint32_t dstArrayElement, vk::DescriptorType descriptorType) {
1075  vk::WriteDescriptorSet wdesc{};
1076  wdesc.dstSet = dstSet_;
1077  wdesc.dstBinding = dstBinding;
1078  wdesc.dstArrayElement = dstArrayElement;
1079  wdesc.descriptorCount = 0;
1080  wdesc.descriptorType = descriptorType;
1081  wdesc.pTexelBufferView = bufferViews_.data() + numBufferViews_;
1082  descriptorWrites_.push_back(wdesc);
1083  }
1084 
1086  void bufferView(vk::BufferView view) {
1087  if (!descriptorWrites_.empty() && numBufferViews_ != bufferViews_.size() && descriptorWrites_.back().pImageInfo) {
1088  descriptorWrites_.back().descriptorCount++;
1089  bufferViews_[numBufferViews_++] = view;
1090  } else {
1091  ok_ = false;
1092  }
1093  }
1094 
1096  void copy(vk::DescriptorSet srcSet, uint32_t srcBinding, uint32_t srcArrayElement, vk::DescriptorSet dstSet, uint32_t dstBinding, uint32_t dstArrayElement, uint32_t descriptorCount) {
1097  descriptorCopies_.emplace_back(srcSet, srcBinding, srcArrayElement, dstSet, dstBinding, dstArrayElement, descriptorCount);
1098  }
1099 
1101  void update(const vk::Device &device) const {
1102  device.updateDescriptorSets( descriptorWrites_, descriptorCopies_ );
1103  }
1104 
1106  bool ok() const { return ok_; }
1107 private:
1108  std::vector<vk::DescriptorBufferInfo> bufferInfo_;
1109  std::vector<vk::DescriptorImageInfo> imageInfo_;
1110  std::vector<vk::WriteDescriptorSet> descriptorWrites_;
1111  std::vector<vk::CopyDescriptorSet> descriptorCopies_;
1112  std::vector<vk::BufferView> bufferViews_;
1113  vk::DescriptorSet dstSet_;
1114  int numBuffers_ = 0;
1115  int numImages_ = 0;
1116  int numBufferViews_ = 0;
1117  bool ok_ = true;
1118 };
1119 
1122 public:
1124  }
1125 
1126  void buffer(uint32_t binding, vk::DescriptorType descriptorType, vk::ShaderStageFlags stageFlags, uint32_t descriptorCount) {
1127  s.bindings.emplace_back(binding, descriptorType, descriptorCount, stageFlags, nullptr);
1128  }
1129 
1130  void image(uint32_t binding, vk::DescriptorType descriptorType, vk::ShaderStageFlags stageFlags, uint32_t descriptorCount) {
1131  s.bindings.emplace_back(binding, descriptorType, descriptorCount, stageFlags, nullptr);
1132  }
1133 
1134  void samplers(uint32_t binding, vk::DescriptorType descriptorType, vk::ShaderStageFlags stageFlags, const std::vector<vk::Sampler> immutableSamplers) {
1135  s.samplers.push_back(immutableSamplers);
1136  auto pImmutableSamplers = s.samplers.back().data();
1137  s.bindings.emplace_back(binding, descriptorType, (uint32_t)immutableSamplers.size(), stageFlags, pImmutableSamplers);
1138  }
1139 
1140  void bufferView(uint32_t binding, vk::DescriptorType descriptorType, vk::ShaderStageFlags stageFlags, uint32_t descriptorCount) {
1141  s.bindings.emplace_back(binding, descriptorType, descriptorCount, stageFlags, nullptr);
1142  }
1143 
1145  vk::UniqueDescriptorSetLayout createUnique(vk::Device device) const {
1146  vk::DescriptorSetLayoutCreateInfo dsci{};
1147  dsci.bindingCount = (uint32_t)s.bindings.size();
1148  dsci.pBindings = s.bindings.data();
1149  return device.createDescriptorSetLayoutUnique(dsci);
1150  }
1151 
1152 private:
1153  struct State {
1154  std::vector<vk::DescriptorSetLayoutBinding> bindings;
1155  std::vector<std::vector<vk::Sampler> > samplers;
1156  int numSamplers = 0;
1157  };
1158 
1159  State s;
1160 };
1161 
1164 public:
1165  // Construct a new, empty DescriptorSetMaker.
1166  DescriptorSetMaker() {
1167  }
1168 
1170  void layout(vk::DescriptorSetLayout layout) {
1171  s.layouts.push_back(layout);
1172  }
1173 
1176  std::vector<vk::DescriptorSet> create(vk::Device device, vk::DescriptorPool descriptorPool) const {
1177  vk::DescriptorSetAllocateInfo dsai{};
1178  dsai.descriptorPool = descriptorPool;
1179  dsai.descriptorSetCount = (uint32_t)s.layouts.size();
1180  dsai.pSetLayouts = s.layouts.data();
1181  return device.allocateDescriptorSets(dsai);
1182  }
1183 
1185  std::vector<vk::UniqueDescriptorSet> createUnique(vk::Device device, vk::DescriptorPool descriptorPool) const {
1186  vk::DescriptorSetAllocateInfo dsai{};
1187  dsai.descriptorPool = descriptorPool;
1188  dsai.descriptorSetCount = (uint32_t)s.layouts.size();
1189  dsai.pSetLayouts = s.layouts.data();
1190  return device.allocateDescriptorSetsUnique(dsai);
1191  }
1192 
1193 private:
1194  struct State {
1195  std::vector<vk::DescriptorSetLayout> layouts;
1196  };
1197 
1198  State s;
1199 };
1200 
1204 public:
1205  GenericImage() {
1206  }
1207 
1208  GenericImage(vk::Device device, const vk::PhysicalDeviceMemoryProperties &memprops, const vk::ImageCreateInfo &info, vk::ImageViewType viewType, vk::ImageAspectFlags aspectMask, bool makeHostImage) {
1209  create(device, memprops, info, viewType, aspectMask, makeHostImage);
1210  }
1211 
1212  vk::Image image() const { return *s.image; }
1213  vk::ImageView imageView() const { return *s.imageView; }
1214  vk::DeviceMemory mem() const { return *s.mem; }
1215 
1217  void clear(vk::CommandBuffer cb, const std::array<float,4> colour = {1, 1, 1, 1}) {
1218  setLayout(cb, vk::ImageLayout::eTransferDstOptimal);
1219  vk::ClearColorValue ccv(colour);
1220  vk::ImageSubresourceRange range{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1};
1221  cb.clearColorImage(*s.image, vk::ImageLayout::eTransferDstOptimal, ccv, range);
1222  }
1223 
1225  void update(vk::Device device, const void *data, vk::DeviceSize bytesPerPixel) {
1226  const uint8_t *src = (const uint8_t *)data;
1227  for (uint32_t mipLevel = 0; mipLevel != info().mipLevels; ++mipLevel) {
1228  // Array images are layed out horizontally. eg. [left][front][right] etc.
1229  for (uint32_t arrayLayer = 0; arrayLayer != info().arrayLayers; ++arrayLayer) {
1230  vk::ImageSubresource subresource{vk::ImageAspectFlagBits::eColor, mipLevel, arrayLayer};
1231  auto srlayout = device.getImageSubresourceLayout(*s.image, subresource);
1232  uint8_t *dest = (uint8_t *)device.mapMemory(*s.mem, 0, s.size, vk::MemoryMapFlags{}) + srlayout.offset;
1233  size_t bytesPerLine = s.info.extent.width * bytesPerPixel;
1234  size_t srcStride = bytesPerLine * info().arrayLayers;
1235  for (int y = 0; y != s.info.extent.height; ++y) {
1236  memcpy(dest, src + arrayLayer * bytesPerLine, bytesPerLine);
1237  src += srcStride;
1238  dest += srlayout.rowPitch;
1239  }
1240  }
1241  }
1242  device.unmapMemory(*s.mem);
1243  }
1244 
1246  void copy(vk::CommandBuffer cb, vku::GenericImage &srcImage) {
1247  srcImage.setLayout(cb, vk::ImageLayout::eTransferSrcOptimal);
1248  setLayout(cb, vk::ImageLayout::eTransferDstOptimal);
1249  for (uint32_t mipLevel = 0; mipLevel != info().mipLevels; ++mipLevel) {
1250  vk::ImageCopy region{};
1251  region.srcSubresource = {vk::ImageAspectFlagBits::eColor, mipLevel, 0, 1};
1252  region.dstSubresource = {vk::ImageAspectFlagBits::eColor, mipLevel, 0, 1};
1253  region.extent = s.info.extent;
1254  cb.copyImage(srcImage.image(), vk::ImageLayout::eTransferSrcOptimal, *s.image, vk::ImageLayout::eTransferDstOptimal, region);
1255  }
1256  }
1257 
1259  void copy(vk::CommandBuffer cb, vk::Buffer buffer, uint32_t mipLevel, uint32_t arrayLayer, uint32_t width, uint32_t height, uint32_t depth, uint32_t offset) {
1260  setLayout(cb, vk::ImageLayout::eTransferDstOptimal);
1261  vk::BufferImageCopy region{};
1262  region.bufferOffset = offset;
1263  vk::Extent3D extent;
1264  extent.width = width;
1265  extent.height = height;
1266  extent.depth = depth;
1267  region.imageSubresource = {vk::ImageAspectFlagBits::eColor, mipLevel, arrayLayer, 1};
1268  region.imageExtent = extent;
1269  cb.copyBufferToImage(buffer, *s.image, vk::ImageLayout::eTransferDstOptimal, region);
1270  }
1271 
1272  void upload(vk::Device device, std::vector<uint8_t> &bytes, vk::CommandPool commandPool, vk::PhysicalDeviceMemoryProperties memprops, vk::Queue queue) {
1273  vku::GenericBuffer stagingBuffer(device, memprops, (vk::BufferUsageFlags)vk::BufferUsageFlagBits::eTransferSrc, (vk::DeviceSize)bytes.size(), vk::MemoryPropertyFlagBits::eHostVisible);
1274  stagingBuffer.updateLocal(device, (const void*)bytes.data(), bytes.size());
1275 
1276  // Copy the staging buffer to the GPU texture and set the layout.
1277  vku::executeImmediately(device, commandPool, queue, [&](vk::CommandBuffer cb) {
1278  auto bp = getBlockParams(s.info.format);
1279  vk::Buffer buf = stagingBuffer.buffer();
1280  uint32_t offset = 0;
1281  for (uint32_t mipLevel = 0; mipLevel != s.info.mipLevels; ++mipLevel) {
1282  auto width = mipScale(s.info.extent.width, mipLevel);
1283  auto height = mipScale(s.info.extent.height, mipLevel);
1284  auto depth = mipScale(s.info.extent.depth, mipLevel);
1285  for (uint32_t face = 0; face != s.info.arrayLayers; ++face) {
1286  copy(cb, buf, mipLevel, face, width, height, depth, offset);
1287  offset += ((bp.bytesPerBlock + 3) & ~3) * (width * height);
1288  }
1289  }
1290  setLayout(cb, vk::ImageLayout::eShaderReadOnlyOptimal);
1291  });
1292  }
1293 
1295  void setLayout(vk::CommandBuffer cb, vk::ImageLayout newLayout, vk::ImageAspectFlags aspectMask = vk::ImageAspectFlagBits::eColor) {
1296  if (newLayout == s.currentLayout) return;
1297  vk::ImageLayout oldLayout = s.currentLayout;
1298  s.currentLayout = newLayout;
1299 
1300  vk::ImageMemoryBarrier imageMemoryBarriers = {};
1301  imageMemoryBarriers.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1302  imageMemoryBarriers.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1303  imageMemoryBarriers.oldLayout = oldLayout;
1304  imageMemoryBarriers.newLayout = newLayout;
1305  imageMemoryBarriers.image = *s.image;
1306  imageMemoryBarriers.subresourceRange = {aspectMask, 0, s.info.mipLevels, 0, s.info.arrayLayers};
1307 
1308  // Put barrier on top
1309  vk::PipelineStageFlags srcStageMask{vk::PipelineStageFlagBits::eTopOfPipe};
1310  vk::PipelineStageFlags dstStageMask{vk::PipelineStageFlagBits::eTopOfPipe};
1311  vk::DependencyFlags dependencyFlags{};
1312  vk::AccessFlags srcMask{};
1313  vk::AccessFlags dstMask{};
1314 
1315  typedef vk::ImageLayout il;
1316  typedef vk::AccessFlagBits afb;
1317 
1318  // Is it me, or are these the same?
1319  switch (oldLayout) {
1320  case il::eUndefined: break;
1321  case il::eGeneral: srcMask = afb::eTransferWrite; break;
1322  case il::eColorAttachmentOptimal: srcMask = afb::eColorAttachmentWrite; break;
1323  case il::eDepthStencilAttachmentOptimal: srcMask = afb::eDepthStencilAttachmentWrite; break;
1324  case il::eDepthStencilReadOnlyOptimal: srcMask = afb::eDepthStencilAttachmentRead; break;
1325  case il::eShaderReadOnlyOptimal: srcMask = afb::eShaderRead; break;
1326  case il::eTransferSrcOptimal: srcMask = afb::eTransferRead; break;
1327  case il::eTransferDstOptimal: srcMask = afb::eTransferWrite; break;
1328  case il::ePreinitialized: srcMask = afb::eTransferWrite|afb::eHostWrite; break;
1329  case il::ePresentSrcKHR: srcMask = afb::eMemoryRead; break;
1330  }
1331 
1332  switch (newLayout) {
1333  case il::eUndefined: break;
1334  case il::eGeneral: dstMask = afb::eTransferWrite; break;
1335  case il::eColorAttachmentOptimal: dstMask = afb::eColorAttachmentWrite; break;
1336  case il::eDepthStencilAttachmentOptimal: dstMask = afb::eDepthStencilAttachmentWrite; break;
1337  case il::eDepthStencilReadOnlyOptimal: dstMask = afb::eDepthStencilAttachmentRead; break;
1338  case il::eShaderReadOnlyOptimal: dstMask = afb::eShaderRead; break;
1339  case il::eTransferSrcOptimal: dstMask = afb::eTransferRead; break;
1340  case il::eTransferDstOptimal: dstMask = afb::eTransferWrite; break;
1341  case il::ePreinitialized: dstMask = afb::eTransferWrite; break;
1342  case il::ePresentSrcKHR: dstMask = afb::eMemoryRead; break;
1343  }
1344 //printf("%08x %08x\n", (VkFlags)srcMask, (VkFlags)dstMask);
1345 
1346  imageMemoryBarriers.srcAccessMask = srcMask;
1347  imageMemoryBarriers.dstAccessMask = dstMask;
1348  auto memoryBarriers = nullptr;
1349  auto bufferMemoryBarriers = nullptr;
1350  cb.pipelineBarrier(srcStageMask, dstStageMask, dependencyFlags, memoryBarriers, bufferMemoryBarriers, imageMemoryBarriers);
1351  }
1352 
1354  void setCurrentLayout(vk::ImageLayout oldLayout) {
1355  s.currentLayout = oldLayout;
1356  }
1357 
1358  vk::Format format() const { return s.info.format; }
1359  vk::Extent3D extent() const { return s.info.extent; }
1360  const vk::ImageCreateInfo &info() const { return s.info; }
1361 protected:
1362  void create(vk::Device device, const vk::PhysicalDeviceMemoryProperties &memprops, const vk::ImageCreateInfo &info, vk::ImageViewType viewType, vk::ImageAspectFlags aspectMask, bool hostImage) {
1363  s.currentLayout = info.initialLayout;
1364  s.info = info;
1365  s.image = device.createImageUnique(info);
1366 
1367  // Find out how much memory and which heap to allocate from.
1368  auto memreq = device.getImageMemoryRequirements(*s.image);
1369  vk::MemoryPropertyFlags search{};
1370  if (hostImage) search = vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible;
1371 
1372  // Create a memory object to bind to the buffer.
1373  // Note: we don't expect to be able to map the buffer.
1374  vk::MemoryAllocateInfo mai{};
1375  mai.allocationSize = s.size = memreq.size;
1376  mai.memoryTypeIndex = vku::findMemoryTypeIndex(memprops, memreq.memoryTypeBits, search);
1377  s.mem = device.allocateMemoryUnique(mai);
1378 
1379  device.bindImageMemory(*s.image, *s.mem, 0);
1380 
1381  if (!hostImage) {
1382  vk::ImageViewCreateInfo viewInfo{};
1383  viewInfo.image = *s.image;
1384  viewInfo.viewType = viewType;
1385  viewInfo.format = info.format;
1386  viewInfo.components = { vk::ComponentSwizzle::eR, vk::ComponentSwizzle::eG, vk::ComponentSwizzle::eB, vk::ComponentSwizzle::eA };
1387  viewInfo.subresourceRange = vk::ImageSubresourceRange{aspectMask, 0, info.mipLevels, 0, info.arrayLayers};
1388  s.imageView = device.createImageViewUnique(viewInfo);
1389  }
1390  }
1391 
1392  struct State {
1393  vk::UniqueImage image;
1394  vk::UniqueImageView imageView;
1395  vk::UniqueDeviceMemory mem;
1396  vk::DeviceSize size;
1397  vk::ImageLayout currentLayout;
1398  vk::ImageCreateInfo info;
1399 
1400  };
1401 
1402  State s;
1403 };
1404 
1405 
1408 public:
1409  TextureImage2D() {
1410  }
1411 
1412  TextureImage2D(vk::Device device, const vk::PhysicalDeviceMemoryProperties &memprops, uint32_t width, uint32_t height, uint32_t mipLevels=1, vk::Format format = vk::Format::eR8G8B8A8Unorm, bool hostImage = false) {
1413  vk::ImageCreateInfo info;
1414  info.flags = {};
1415  info.imageType = vk::ImageType::e2D;
1416  info.format = format;
1417  info.extent = vk::Extent3D{ width, height, 1U };
1418  info.mipLevels = mipLevels;
1419  info.arrayLayers = 1;
1420  info.samples = vk::SampleCountFlagBits::e1;
1421  info.tiling = hostImage ? vk::ImageTiling::eLinear : vk::ImageTiling::eOptimal;
1422  info.usage = vk::ImageUsageFlagBits::eSampled|vk::ImageUsageFlagBits::eTransferSrc|vk::ImageUsageFlagBits::eTransferDst;
1423  info.sharingMode = vk::SharingMode::eExclusive;
1424  info.queueFamilyIndexCount = 0;
1425  info.pQueueFamilyIndices = nullptr;
1426  info.initialLayout = hostImage ? vk::ImageLayout::ePreinitialized : vk::ImageLayout::eUndefined;
1427  create(device, memprops, info, vk::ImageViewType::e2D, vk::ImageAspectFlagBits::eColor, hostImage);
1428  }
1429 private:
1430 };
1431 
1434 public:
1435  TextureImageCube() {
1436  }
1437 
1438  TextureImageCube(vk::Device device, const vk::PhysicalDeviceMemoryProperties &memprops, uint32_t width, uint32_t height, uint32_t mipLevels=1, vk::Format format = vk::Format::eR8G8B8A8Unorm, bool hostImage = false) {
1439  vk::ImageCreateInfo info;
1440  info.flags = {vk::ImageCreateFlagBits::eCubeCompatible};
1441  info.imageType = vk::ImageType::e2D;
1442  info.format = format;
1443  info.extent = vk::Extent3D{ width, height, 1U };
1444  info.mipLevels = mipLevels;
1445  info.arrayLayers = 6;
1446  info.samples = vk::SampleCountFlagBits::e1;
1447  info.tiling = hostImage ? vk::ImageTiling::eLinear : vk::ImageTiling::eOptimal;
1448  info.usage = vk::ImageUsageFlagBits::eSampled|vk::ImageUsageFlagBits::eTransferSrc|vk::ImageUsageFlagBits::eTransferDst;
1449  info.sharingMode = vk::SharingMode::eExclusive;
1450  info.queueFamilyIndexCount = 0;
1451  info.pQueueFamilyIndices = nullptr;
1452  //info.initialLayout = hostImage ? vk::ImageLayout::ePreinitialized : vk::ImageLayout::eUndefined;
1453  info.initialLayout = vk::ImageLayout::ePreinitialized;
1454  create(device, memprops, info, vk::ImageViewType::eCube, vk::ImageAspectFlagBits::eColor, hostImage);
1455  }
1456 private:
1457 };
1458 
1461 public:
1462  DepthStencilImage() {
1463  }
1464 
1465  DepthStencilImage(vk::Device device, const vk::PhysicalDeviceMemoryProperties &memprops, uint32_t width, uint32_t height, vk::Format format = vk::Format::eD24UnormS8Uint) {
1466  vk::ImageCreateInfo info;
1467  info.flags = {};
1468 
1469  info.imageType = vk::ImageType::e2D;
1470  info.format = format;
1471  info.extent = vk::Extent3D{ width, height, 1U };
1472  info.mipLevels = 1;
1473  info.arrayLayers = 1;
1474  info.samples = vk::SampleCountFlagBits::e1;
1475  info.tiling = vk::ImageTiling::eOptimal;
1476  info.usage = vk::ImageUsageFlagBits::eDepthStencilAttachment|vk::ImageUsageFlagBits::eTransferSrc|vk::ImageUsageFlagBits::eSampled;
1477  info.sharingMode = vk::SharingMode::eExclusive;
1478  info.queueFamilyIndexCount = 0;
1479  info.pQueueFamilyIndices = nullptr;
1480  info.initialLayout = vk::ImageLayout::eUndefined;
1481  typedef vk::ImageAspectFlagBits iafb;
1482  create(device, memprops, info, vk::ImageViewType::e2D, iafb::eDepth, false);
1483  }
1484 private:
1485 };
1486 
1489 public:
1491  }
1492 
1493  ColorAttachmentImage(vk::Device device, const vk::PhysicalDeviceMemoryProperties &memprops, uint32_t width, uint32_t height, vk::Format format = vk::Format::eR8G8B8A8Unorm) {
1494  vk::ImageCreateInfo info;
1495  info.flags = {};
1496 
1497  info.imageType = vk::ImageType::e2D;
1498  info.format = format;
1499  info.extent = vk::Extent3D{ width, height, 1U };
1500  info.mipLevels = 1;
1501  info.arrayLayers = 1;
1502  info.samples = vk::SampleCountFlagBits::e1;
1503  info.tiling = vk::ImageTiling::eOptimal;
1504  info.usage = vk::ImageUsageFlagBits::eColorAttachment|vk::ImageUsageFlagBits::eTransferSrc|vk::ImageUsageFlagBits::eSampled;
1505  info.sharingMode = vk::SharingMode::eExclusive;
1506  info.queueFamilyIndexCount = 0;
1507  info.pQueueFamilyIndices = nullptr;
1508  info.initialLayout = vk::ImageLayout::eUndefined;
1509  typedef vk::ImageAspectFlagBits iafb;
1510  create(device, memprops, info, vk::ImageViewType::e2D, iafb::eColor, false);
1511  }
1512 private:
1513 };
1514 
1521 public:
1524  s.info.magFilter = vk::Filter::eNearest;
1525  s.info.minFilter = vk::Filter::eNearest;
1526  s.info.mipmapMode = vk::SamplerMipmapMode::eNearest;
1527  s.info.addressModeU = vk::SamplerAddressMode::eRepeat;
1528  s.info.addressModeV = vk::SamplerAddressMode::eRepeat;
1529  s.info.addressModeW = vk::SamplerAddressMode::eRepeat;
1530  s.info.mipLodBias = 0.0f;
1531  s.info.anisotropyEnable = 0;
1532  s.info.maxAnisotropy = 0.0f;
1533  s.info.compareEnable = 0;
1534  s.info.compareOp = vk::CompareOp::eNever;
1535  s.info.minLod = 0;
1536  s.info.maxLod = 0;
1537  s.info.borderColor = vk::BorderColor{};
1538  s.info.unnormalizedCoordinates = 0;
1539  }
1540 
1542  //
1543  // Setters
1544  //
1545  SamplerMaker &flags(vk::SamplerCreateFlags value) { s.info.flags = value; return *this; }
1546 
1549  SamplerMaker &magFilter(vk::Filter value) { s.info.magFilter = value; return *this; }
1550 
1553  SamplerMaker &minFilter(vk::Filter value) { s.info.minFilter = value; return *this; }
1554 
1557  SamplerMaker &mipmapMode(vk::SamplerMipmapMode value) { s.info.mipmapMode = value; return *this; }
1558  SamplerMaker &addressModeU(vk::SamplerAddressMode value) { s.info.addressModeU = value; return *this; }
1559  SamplerMaker &addressModeV(vk::SamplerAddressMode value) { s.info.addressModeV = value; return *this; }
1560  SamplerMaker &addressModeW(vk::SamplerAddressMode value) { s.info.addressModeW = value; return *this; }
1561  SamplerMaker &mipLodBias(float value) { s.info.mipLodBias = value; return *this; }
1562  SamplerMaker &anisotropyEnable(vk::Bool32 value) { s.info.anisotropyEnable = value; return *this; }
1563  SamplerMaker &maxAnisotropy(float value) { s.info.maxAnisotropy = value; return *this; }
1564  SamplerMaker &compareEnable(vk::Bool32 value) { s.info.compareEnable = value; return *this; }
1565  SamplerMaker &compareOp(vk::CompareOp value) { s.info.compareOp = value; return *this; }
1566  SamplerMaker &minLod(float value) { s.info.minLod = value; return *this; }
1567  SamplerMaker &maxLod(float value) { s.info.maxLod = value; return *this; }
1568  SamplerMaker &borderColor(vk::BorderColor value) { s.info.borderColor = value; return *this; }
1569  SamplerMaker &unnormalizedCoordinates(vk::Bool32 value) { s.info.unnormalizedCoordinates = value; return *this; }
1570 
1572  vk::UniqueSampler createUnique(vk::Device device) const {
1573  return device.createSamplerUnique(s.info);
1574  }
1575 
1577  vk::Sampler create(vk::Device device) const {
1578  return device.createSampler(s.info);
1579  }
1580 
1581 private:
1582  struct State {
1583  vk::SamplerCreateInfo info;
1584  };
1585 
1586  State s;
1587 };
1588 
1590 inline vk::Format GLtoVKFormat(uint32_t glFormat) {
1591  switch (glFormat) {
1592  case 0x1907: return vk::Format::eR8G8B8Unorm; // GL_RGB
1593  case 0x1908: return vk::Format::eR8G8B8A8Unorm; // GL_RGBA
1594  case 0x83F0: return vk::Format::eBc1RgbUnormBlock; // GL_COMPRESSED_RGB_S3TC_DXT1_EXT
1595  case 0x83F1: return vk::Format::eBc1RgbaUnormBlock; // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
1596  case 0x83F2: return vk::Format::eBc3UnormBlock; // GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
1597  case 0x83F3: return vk::Format::eBc5UnormBlock; // GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
1598  }
1599  return vk::Format::eUndefined;
1600 }
1601 
1602 
1603 
1606 public:
1607  KTXFileLayout() {
1608  }
1609 
1610  KTXFileLayout(uint8_t *begin, uint8_t *end) {
1611  uint8_t *p = begin;
1612  if (p + sizeof(Header) > end) return;
1613  header = *(Header*)p;
1614  static const uint8_t magic[] = {
1615  0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
1616  };
1617 
1618 
1619  if (memcmp(magic, header.identifier, sizeof(magic))) {
1620  return;
1621  }
1622 
1623  if (header.endianness != 0x04030201) {
1624  swap(header.glType);
1625  swap(header.glTypeSize);
1626  swap(header.glFormat);
1627  swap(header.glInternalFormat);
1628  swap(header.glBaseInternalFormat);
1629  swap(header.pixelWidth);
1630  swap(header.pixelHeight);
1631  swap(header.pixelDepth);
1632  swap(header.numberOfArrayElements);
1633  swap(header.numberOfFaces);
1634  swap(header.numberOfMipmapLevels);
1635  swap(header.bytesOfKeyValueData);
1636  }
1637 
1638  header.numberOfArrayElements = std::max(1U, header.numberOfArrayElements);
1639  header.numberOfFaces = std::max(1U, header.numberOfFaces);
1640  header.numberOfMipmapLevels = std::max(1U, header.numberOfMipmapLevels);
1641  header.pixelDepth = std::max(1U, header.pixelDepth);
1642 
1643  format_ = GLtoVKFormat(header.glFormat);
1644  if (format_ == vk::Format::eUndefined) return;
1645 
1646  p += sizeof(Header);
1647  if (p + header.bytesOfKeyValueData > end) return;
1648 
1649  for (uint32_t i = 0; i < header.bytesOfKeyValueData; ) {
1650  uint32_t keyAndValueByteSize = *(uint32_t*)(p + i);
1651  if (header.endianness != 0x04030201) swap(keyAndValueByteSize);
1652  std::string kv(p + i + 4, p + i + 4 + keyAndValueByteSize);
1653  i += keyAndValueByteSize + 4;
1654  i = (i + 3) & ~3;
1655  }
1656 
1657  p += header.bytesOfKeyValueData;
1658  for (uint32_t mipLevel = 0; mipLevel != header.numberOfMipmapLevels; ++mipLevel) {
1659  uint32_t imageSize = *(uint32_t*)(p);
1660  imageSize = (imageSize + 3) & ~3;
1661  uint32_t incr = imageSize * header.numberOfFaces * header.numberOfArrayElements;
1662  incr = (incr + 3) & ~3;
1663 
1664  if (p + incr > end) {
1665  // see https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPixelStore.xhtml
1666  // fix bugs... https://github.com/dariomanesku/cmft/issues/29
1667  header.numberOfMipmapLevels = mipLevel;
1668  break;
1669  }
1670 
1671  if (header.endianness != 0x04030201) swap(imageSize);
1672  //printf("%08x: is=%08x / %08x\n", p-begin, imageSize, end - begin);
1673  p += 4;
1674  imageOffsets_.push_back((uint32_t)(p - begin));
1675  imageSizes_.push_back(imageSize);
1676  p += incr;
1677  }
1678 
1679  ok_ = true;
1680  }
1681 
1682  uint32_t offset(uint32_t mipLevel, uint32_t arrayLayer, uint32_t face) {
1683  return imageOffsets_[mipLevel] + (arrayLayer * header.numberOfFaces + face) * imageSizes_[mipLevel];
1684  }
1685 
1686  uint32_t size(uint32_t mipLevel) {
1687  return imageSizes_[mipLevel];
1688  }
1689 
1690  bool ok() const { return ok_; }
1691  vk::Format format() const { return format_; }
1692  uint32_t mipLevels() const { return header.numberOfMipmapLevels; }
1693  uint32_t arrayLayers() const { return header.numberOfArrayElements; }
1694  uint32_t faces() const { return header.numberOfFaces; }
1695  uint32_t width(uint32_t mipLevel) const { return mipScale(header.pixelWidth, mipLevel); }
1696  uint32_t height(uint32_t mipLevel) const { return mipScale(header.pixelHeight, mipLevel); }
1697  uint32_t depth(uint32_t mipLevel) const { return mipScale(header.pixelDepth, mipLevel); }
1698 
1699  void upload(vk::Device device, vku::GenericImage &image, std::vector<uint8_t> &bytes, vk::CommandPool commandPool, vk::PhysicalDeviceMemoryProperties memprops, vk::Queue queue) {
1700  vku::GenericBuffer stagingBuffer(device, memprops, (vk::BufferUsageFlags)vk::BufferUsageFlagBits::eTransferSrc, (vk::DeviceSize)bytes.size(), vk::MemoryPropertyFlagBits::eHostVisible);
1701  stagingBuffer.updateLocal(device, (const void*)bytes.data(), bytes.size());
1702 
1703  // Copy the staging buffer to the GPU texture and set the layout.
1704  vku::executeImmediately(device, commandPool, queue, [&](vk::CommandBuffer cb) {
1705  vk::Buffer buf = stagingBuffer.buffer();
1706  for (uint32_t mipLevel = 0; mipLevel != mipLevels(); ++mipLevel) {
1707  auto width = this->width(mipLevel);
1708  auto height = this->height(mipLevel);
1709  auto depth = this->depth(mipLevel);
1710  for (uint32_t face = 0; face != faces(); ++face) {
1711  image.copy(cb, buf, mipLevel, face, width, height, depth, offset(mipLevel, 0, face));
1712  }
1713  }
1714  image.setLayout(cb, vk::ImageLayout::eShaderReadOnlyOptimal);
1715  });
1716  }
1717 
1718 private:
1719  static void swap(uint32_t &value) {
1720  value = value >> 24 | (value & 0xff0000) >> 8 | (value & 0xff00) << 8 | value << 24;
1721  }
1722 
1723  struct Header {
1724  uint8_t identifier[12];
1725  uint32_t endianness;
1726  uint32_t glType;
1727  uint32_t glTypeSize;
1728  uint32_t glFormat;
1729  uint32_t glInternalFormat;
1730  uint32_t glBaseInternalFormat;
1731  uint32_t pixelWidth;
1732  uint32_t pixelHeight;
1733  uint32_t pixelDepth;
1734  uint32_t numberOfArrayElements;
1735  uint32_t numberOfFaces;
1736  uint32_t numberOfMipmapLevels;
1737  uint32_t bytesOfKeyValueData;
1738  };
1739 
1740  Header header;
1741  vk::Format format_;
1742  bool ok_ = false;
1743  std::vector<uint32_t> imageOffsets_;
1744  std::vector<uint32_t> imageSizes_;
1745 };
1746 
1747 
1748 } // namespace vku
1749 
1750 #endif // VKU_HPP
std::vector< vk::UniqueDescriptorSet > createUnique(vk::Device device, vk::DescriptorPool descriptorPool) const
Allocate a vector of self-deleting descriptor sets.
Definition: vku.hpp:1185
void vertexBinding(uint32_t binding_, uint32_t stride_, vk::VertexInputRate inputRate_=vk::VertexInputRate::eVertex)
Definition: vku.hpp:735
SamplerMaker()
Default to a very basic sampler.
Definition: vku.hpp:1523
vk::UniquePipeline createUnique(vk::Device device, const vk::PipelineCache &pipelineCache, const vk::PipelineLayout &pipelineLayout)
Create a managed handle to a compute shader.
Definition: vku.hpp:848
std::vector< vk::DescriptorSet > create(vk::Device device, vk::DescriptorPool descriptorPool) const
Definition: vku.hpp:1176
vk::UniqueDescriptorSetLayout createUnique(vk::Device device) const
Create a self-deleting descriptor set object.
Definition: vku.hpp:1145
PipelineMaker & primitiveRestartEnable(vk::Bool32 primitiveRestartEnable)
Definition: vku.hpp:752
Definition: vku.hpp:862
void blendSrcColorBlendFactor(vk::BlendFactor value)
Source colour blend factor (called after blendBegin())
Definition: vku.hpp:702
void copy(vk::CommandBuffer cb, vk::Buffer buffer, uint32_t mipLevel, uint32_t arrayLayer, uint32_t width, uint32_t height, uint32_t depth, uint32_t offset)
Copy a subimage in a buffer to this image.
Definition: vku.hpp:1259
Definition: vku.hpp:982
ShaderModule(const vk::Device &device, const std::string &filename)
Construct a shader module from a file.
Definition: vku.hpp:410
A factory class for descriptor sets (A set of uniform bindings)
Definition: vku.hpp:1163
void blendDstAlphaBlendFactor(vk::BlendFactor value)
Destination alpha blend factor (called after blendBegin())
Definition: vku.hpp:714
Convenience class for updating descriptor sets (uniforms)
Definition: vku.hpp:1015
void blendAlphaBlendOp(vk::BlendOp value)
Alpha operation (called after blendBegin())
Definition: vku.hpp:717
void descriptorSetLayout(vk::DescriptorSetLayout layout)
Add a descriptor set layout to the pipeline.
Definition: vku.hpp:566
void vertexAttribute(uint32_t location_, uint32_t binding_, vk::Format format_, uint32_t offset_)
Add a vertex attribute to the pipeline.
Definition: vku.hpp:723
void setCurrentLayout(vk::ImageLayout oldLayout)
Set what the image thinks is its current layout (ie. the old layout in an image barrier).
Definition: vku.hpp:1354
std::ostream & write(std::ostream &os)
Definition: vku.hpp:519
void blendEnable(vk::Bool32 value)
Enable or disable blending (called after blendBegin())
Definition: vku.hpp:699
Definition: vku.hpp:1203
void subpassBegin(vk::PipelineBindPoint bp)
Definition: vku.hpp:334
vk::UniqueSampler createUnique(vk::Device device) const
Allocate a self-deleting image.
Definition: vku.hpp:1572
void executeImmediately(vk::Device device, vk::CommandPool commandPool, vk::Queue queue, const std::function< void(vk::CommandBuffer cb)> &func)
Execute commands immediately and wait for the device to finish.
Definition: vku.hpp:58
Definition: vku.hpp:552
void vertexAttribute(const vk::VertexInputAttributeDescription &desc)
Add a vertex attribute to the pipeline.
Definition: vku.hpp:728
PipelineMaker & viewport(const vk::Viewport &value)
Definition: vku.hpp:760
vk::Sampler create(vk::Device device) const
Allocate a non self-deleting Sampler.
Definition: vku.hpp:1577
Definition: vku.hpp:959
void beginImages(uint32_t dstBinding, uint32_t dstArrayElement, vk::DescriptorType descriptorType)
Call this to begin a new set of images.
Definition: vku.hpp:1030
Definition: vku.hpp:1520
SamplerMaker & minFilter(vk::Filter value)
Definition: vku.hpp:1553
This class is a specialisation of GenericBuffer for uniform buffers.
Definition: vku.hpp:1004
Definition: vku.hpp:309
void beginBuffers(uint32_t dstBinding, uint32_t dstArrayElement, vk::DescriptorType descriptorType)
Call this to start defining buffers.
Definition: vku.hpp:1052
SamplerMaker & magFilter(vk::Filter value)
Definition: vku.hpp:1549
void update(const vk::Device &device) const
Call this to update the descriptor sets with their pointers (but not data).
Definition: vku.hpp:1101
void shader(vk::ShaderStageFlagBits stage, vku::ShaderModule &shader, const char *entryPoint="main")
Add a shader module to the pipeline.
Definition: vku.hpp:835
A class for building compute pipelines.
Definition: vku.hpp:829
BlockParams getBlockParams(vk::Format format)
Get the details of vulkan texture formats.
Definition: vku.hpp:102
void shader(vk::ShaderStageFlagBits stage, vku::ShaderModule &shader, const char *entryPoint="main")
Add a shader module to the pipeline.
Definition: vku.hpp:661
SamplerMaker & mipmapMode(vk::SamplerMipmapMode value)
Definition: vku.hpp:1557
void blendColorWriteMask(vk::ColorComponentFlags value)
Colour write mask (called after blendBegin())
Definition: vku.hpp:720
void update(vk::Device device, const void *data, vk::DeviceSize bytesPerPixel)
Update the image with an array of pixels. (Currently 2D only)
Definition: vku.hpp:1225
uint32_t mipScale(uint32_t value, uint32_t mipLevel)
Scale a value by mip level, but do not reduce to zero.
Definition: vku.hpp:76
PipelineMaker & inputAssemblyState(const vk::PipelineInputAssemblyStateCreateInfo &value)
Definition: vku.hpp:756
PipelineMaker & colorBlendState(const vk::PipelineColorBlendStateCreateInfo &value)
Definition: vku.hpp:806
void clear(vk::CommandBuffer cb, const std::array< float, 4 > colour={1, 1, 1, 1})
Clear the colour of an image.
Definition: vku.hpp:1217
void beginDescriptorSet(vk::DescriptorSet dstSet)
Call this to begin a new descriptor set.
Definition: vku.hpp:1025
void upload(vk::Device device, const vk::PhysicalDeviceMemoryProperties &memprops, vk::CommandPool commandPool, vk::Queue queue, const void *value, vk::DeviceSize size) const
Definition: vku.hpp:897
void blendDstColorBlendFactor(vk::BlendFactor value)
Destination colour blend factor (called after blendBegin())
Definition: vku.hpp:705
void blendSrcAlphaBlendFactor(vk::BlendFactor value)
Source alpha blend factor (called after blendBegin())
Definition: vku.hpp:711
PipelineMaker & rasterizationState(const vk::PipelineRasterizationStateCreateInfo &value)
Definition: vku.hpp:768
void beginBufferViews(uint32_t dstBinding, uint32_t dstArrayElement, vk::DescriptorType descriptorType)
Call this to start adding buffer views. (for example, writable images).
Definition: vku.hpp:1074
void attachmentBegin(vk::Format format)
Definition: vku.hpp:316
Layout of a KTX file in a buffer.
Definition: vku.hpp:1605
A factory class for descriptor set layouts. (An interface to the shaders)
Definition: vku.hpp:1121
PipelineMaker & multisampleState(const vk::PipelineMultisampleStateCreateInfo &value)
Definition: vku.hpp:783
void blendBegin(vk::Bool32 enable)
Definition: vku.hpp:684
std::string format(const char *fmt, Args...args)
Printf-style formatting function.
Definition: vku.hpp:38
std::vector< uint8_t > loadFile(const std::string &filename)
Definition: vku.hpp:82
void pushConstantRange(vk::ShaderStageFlags stageFlags_, uint32_t offset_, uint32_t size_)
Definition: vku.hpp:572
void colorBlend(const vk::PipelineColorBlendAttachmentState &state)
Definition: vku.hpp:672
Definition: vku.hpp:1392
void bufferView(vk::BufferView view)
Call this to add a buffer view. (Texel images)
Definition: vku.hpp:1086
int findMemoryTypeIndex(const vk::PhysicalDeviceMemoryProperties &memprops, uint32_t memoryTypeBits, vk::MemoryPropertyFlags search)
Utility function for finding memory types for uniforms and images.
Definition: vku.hpp:46
An image to use as a colour buffer on a renderpass.
Definition: vku.hpp:1488
void layout(vk::DescriptorSetLayout layout)
Add another layout describing a descriptor set.
Definition: vku.hpp:1170
PipelineMaker & topology(vk::PrimitiveTopology topology)
Definition: vku.hpp:748
Description of blocks for compressed formats.
Definition: vku.hpp:95
A variable in a shader.
Definition: vku.hpp:444
PipelineMaker & scissor(const vk::Rect2D &value)
Definition: vku.hpp:764
bool ok() const
Returns true if the updater is error free.
Definition: vku.hpp:1106
UniformBuffer(const vk::Device &device, const vk::PhysicalDeviceMemoryProperties &memprops, size_t size)
Device local uniform buffer.
Definition: vku.hpp:1010
This class is a specialisation of GenericBuffer for low performance vertex buffers on the host...
Definition: vku.hpp:969
A 2D texture image living on the GPU or a staging buffer visible to the CPU.
Definition: vku.hpp:1407
void image(vk::Sampler sampler, vk::ImageView imageView, vk::ImageLayout imageLayout)
Call this to add a combined image sampler.
Definition: vku.hpp:1042
void vertexBinding(const vk::VertexInputBindingDescription &desc)
Definition: vku.hpp:742
void updateLocal(const vk::Device &device, const void *value, vk::DeviceSize size) const
For a host buffer, copy memory to the buffer object.
Definition: vku.hpp:888
void copy(vk::CommandBuffer cb, vku::GenericImage &srcImage)
Copy another image to this one. This also changes the layout.
Definition: vku.hpp:1246
Definition: vku.hpp:587
void copy(vk::DescriptorSet srcSet, uint32_t srcBinding, uint32_t srcArrayElement, vk::DescriptorSet dstSet, uint32_t dstBinding, uint32_t dstArrayElement, uint32_t descriptorCount)
Copy an existing descriptor.
Definition: vku.hpp:1096
Class for building shader modules and extracting metadata from shaders.
Definition: vku.hpp:404
std::vector< Variable > getVariables() const
Definition: vku.hpp:469
vk::UniquePipelineLayout createUnique(const vk::Device &device) const
Create a self-deleting pipeline layout object.
Definition: vku.hpp:557
void blendColorBlendOp(vk::BlendOp value)
Blend operation (called after blendBegin())
Definition: vku.hpp:708
vk::Format GLtoVKFormat(uint32_t glFormat)
KTX files use OpenGL format values. This converts some common ones to Vulkan equivalents.
Definition: vku.hpp:1590
ShaderModule(const vk::Device &device, InIter begin, InIter end)
Construct a shader module from a memory.
Definition: vku.hpp:433
void setLayout(vk::CommandBuffer cb, vk::ImageLayout newLayout, vk::ImageAspectFlags aspectMask=vk::ImageAspectFlagBits::eColor)
Change the layout of this image using a memory barrier.
Definition: vku.hpp:1295
ComputePipelineMaker & module(const vk::PipelineShaderStageCreateInfo &value)
Set the compute shader module.
Definition: vku.hpp:843
void buffer(vk::Buffer buffer, vk::DeviceSize offset, vk::DeviceSize range)
Call this to add a new buffer.
Definition: vku.hpp:1064
PipelineMaker & depthStencilState(const vk::PipelineDepthStencilStateCreateInfo &value)
Definition: vku.hpp:793
An image to use as a depth buffer on a renderpass.
Definition: vku.hpp:1460
This class is a specialisation of GenericBuffer for low performance vertex buffers in CPU memory...
Definition: vku.hpp:992
A cube map texture image living on the GPU or a staging buffer visible to the CPU.
Definition: vku.hpp:1433
Vookoo high level C++ Vulkan interface.
Definition: vku.hpp:34