master
ブランチ master
VulkanExample / VulkanExample / main.cc
43.6 KB、1130行 生 Blame 履歴
1#define NOMINMAX
2//#define VULKAN_HPP_NO_EXCEPTIONS
3
4#pragma region headers
5#include <util/file.hh>
6#include <shader/slang.hh>
7#include <shader/glsl.hh>
8
9#include <iostream>
10#include <map>
11#include <ranges>
12#include <algorithm>
13#include <limits>
14#include <fstream>
15#include <array>
16#include <chrono>
17#include <cassert>
18
19#include <util/root.hh>
20
21#define STB_IMAGE_IMPLEMENTATION
22#include <stb_image.hh>
23
24VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
25
26constexpr int MAX_FRAMES_IN_FLIGHT = 2;
27uint32_t frameIdx = 0;
28
29bool framebufferResized = false;
30
31std::vector<vk::Image> swapChainImages;
32vk::CommandPool cmdPool;
33vk::CommandBuffer cmdBuf;
34vk::CommandBufferBeginInfo beginInfo;
35vk::Queue gfxQueue;
36vk::PipelineLayout pipelineLayout;
37std::vector<vk::ImageView> swapChainImageViews;
38vk::Extent2D swapChainExtent;
39vk::Pipeline gfxPipeline;
40vk::PhysicalDevice physicalDevice;
41vk::Device device;
42vk::SurfaceKHR surface;
43vk::SwapchainKHR swapChain = nullptr;
44vk::SurfaceFormatKHR swapChainFormat;
45vk::SurfaceCapabilitiesKHR surfaceCapabilities;
46std::vector<vk::SurfaceFormatKHR> availFormats;
47std::vector<vk::PresentModeKHR> availPresentModes;
48GLFWwindow *window;
49
50vk::DescriptorSetLayout descriptorSetLayout = nullptr;
51vk::DescriptorPool descriptorPool = nullptr;
52std::vector<vk::DescriptorSet> descriptorSets;
53
54vk::Buffer vertBuf = nullptr;
55vk::DeviceMemory vertBufMem = nullptr;
56vk::Buffer idxBuf = nullptr;
57vk::DeviceMemory idxBufMem = nullptr;
58
59vk::Image texImg = nullptr;
60vk::DeviceMemory texImgMem = nullptr;
61vk::ImageView texImgView = nullptr;
62vk::Sampler texSampler = nullptr;
63
64std::vector<vk::Buffer> uniformBufs;
65std::vector<vk::DeviceMemory> uniformBufsMem;
66std::vector<void *> uniformBufsMapped;
67
68#pragma region debugCallback
69static VKAPI_ATTR vk::Bool32 VKAPI_CALL debugCallback(
70 vk::DebugUtilsMessageSeverityFlagBitsEXT severity,
71 vk::DebugUtilsMessageTypeFlagsEXT type,
72 const vk::DebugUtilsMessengerCallbackDataEXT *pCallbackData,
73 void *pUserData) {
74 if (severity >= vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning) {
75 std::cerr << "validation layer: type " << to_string(type)
76 << " msg: " << pCallbackData->pMessage << std::endl;
77 }
78
79 return vk::False;
80}
81#pragma endregion
82
83#pragma region findMemoryType
84uint32_t findMemoryType(uint32_t typeFilter, vk::MemoryPropertyFlags props) {
85 vk::PhysicalDeviceMemoryProperties memProps = physicalDevice.getMemoryProperties();
86
87 for (uint32_t i = 0; i < memProps.memoryTypeCount; ++i) {
88 if ((typeFilter & (1 << i)) && (memProps.memoryTypes[i].propertyFlags & props) == props) return i;
89 }
90
91 return 0;
92}
93#pragma endregion
94
95#pragma region transitionImgLayout
96void transitionImgLayout(uint32_t imgIdx,
97 vk::ImageLayout oldLayout,
98 vk::ImageLayout newLayout,
99 vk::AccessFlags2 srcAccessMask,
100 vk::AccessFlags2 dstAccessMask,
101 vk::PipelineStageFlags2 srcStageMask,
102 vk::PipelineStageFlags2 dstStageMask) {
103 vk::ImageSubresourceRange barrierSubres = {};
104 barrierSubres.aspectMask = vk::ImageAspectFlagBits::eColor;
105 barrierSubres.baseMipLevel = 0;
106 barrierSubres.levelCount = 1;
107 barrierSubres.baseArrayLayer = 0;
108 barrierSubres.layerCount = 1;
109
110 vk::ImageMemoryBarrier2 barrier = {};
111 barrier.srcStageMask = srcStageMask;
112 barrier.dstStageMask = dstStageMask;
113 barrier.srcAccessMask = srcAccessMask;
114 barrier.dstAccessMask = dstAccessMask;
115 barrier.oldLayout = oldLayout;
116 barrier.newLayout = newLayout;
117 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
118 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
119 barrier.image = swapChainImages[imgIdx];
120 barrier.subresourceRange = barrierSubres;
121
122 vk::DependencyInfo depInfo = {};
123 depInfo.dependencyFlags = {};
124 depInfo.imageMemoryBarrierCount = 1;
125 depInfo.pImageMemoryBarriers = &barrier;
126
127 cmdBuf.pipelineBarrier2(depInfo);
128}
129#pragma endregion
130
131#pragma region framebufferResizeCallback
132static void framebufferResizeCallback(GLFWwindow *window, int width, int height) {
133 framebufferResized = true;
134}
135#pragma endregion
136
137#pragma region swapchain
138void createSwapChain(vk::SwapchainKHR oldSwapChain = nullptr) {
139 surfaceCapabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface);
140 availFormats = physicalDevice.getSurfaceFormatsKHR(surface);
141 availPresentModes = physicalDevice.getSurfacePresentModesKHR(surface);
142 assert(!availFormats.empty());
143
144 const auto formatIt = std::ranges::find_if(availFormats, [](const auto &format) {
145 return format.format == vk::Format::eB8G8R8A8Srgb && format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear;
146 });
147
148 swapChainFormat = formatIt != availFormats.end() ? *formatIt : availFormats[0];
149
150 assert(std::ranges::any_of(availPresentModes, [](auto present) { return present == vk::PresentModeKHR::eFifo; }));
151 vk::PresentModeKHR presentMode = std::ranges::any_of(availPresentModes, [](const vk::PresentModeKHR val) {
152 return vk::PresentModeKHR::eMailbox == val;
153 }) ? vk::PresentModeKHR::eMailbox : vk::PresentModeKHR::eFifo;
154
155 if (surfaceCapabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
156 swapChainExtent = surfaceCapabilities.currentExtent;
157 } else {
158 int width, height;
159 glfwGetFramebufferSize(window, &width, &height);
160 swapChainExtent.width = std::clamp<uint32_t>(width, surfaceCapabilities.minImageExtent.width, surfaceCapabilities.maxImageExtent.width);
161 swapChainExtent.height = std::clamp<uint32_t>(height, surfaceCapabilities.minImageExtent.height, surfaceCapabilities.maxImageExtent.height);
162 }
163
164 uint32_t minImageCount = std::max(3u, surfaceCapabilities.minImageCount);
165 if ((0 < surfaceCapabilities.maxImageCount) && (surfaceCapabilities.maxImageCount < minImageCount)) {
166 minImageCount = surfaceCapabilities.maxImageCount;
167 }
168
169 vk::SwapchainCreateInfoKHR swapChainCreateInfo = {};
170 swapChainCreateInfo.surface = surface;
171 swapChainCreateInfo.minImageCount = minImageCount;
172 swapChainCreateInfo.imageFormat = swapChainFormat.format;
173 swapChainCreateInfo.imageColorSpace = swapChainFormat.colorSpace;
174 swapChainCreateInfo.imageExtent = swapChainExtent;
175 swapChainCreateInfo.imageArrayLayers = 1;
176 swapChainCreateInfo.imageUsage = vk::ImageUsageFlagBits::eColorAttachment;
177 swapChainCreateInfo.imageSharingMode = vk::SharingMode::eExclusive;
178 swapChainCreateInfo.preTransform = surfaceCapabilities.currentTransform;
179 swapChainCreateInfo.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque;
180 swapChainCreateInfo.presentMode = presentMode;
181 swapChainCreateInfo.clipped = true;
182 swapChainCreateInfo.oldSwapchain = oldSwapChain;
183
184 swapChain = device.createSwapchainKHR(swapChainCreateInfo);
185 swapChainImages = device.getSwapchainImagesKHR(swapChain);
186}
187
188vk::ImageView createImageView(const vk::Image &image, vk::Format format) {
189 vk::ImageSubresourceRange subrange = {};
190 subrange.aspectMask = vk::ImageAspectFlagBits::eColor;
191 subrange.baseMipLevel = 0;
192 subrange.levelCount = 1;
193 subrange.baseArrayLayer = 0;
194 subrange.layerCount = 1;
195
196 vk::ImageViewCreateInfo imgViewCreateInfo = {};
197 imgViewCreateInfo.image = image;
198 imgViewCreateInfo.viewType = vk::ImageViewType::e2D;
199 imgViewCreateInfo.format = format;
200 imgViewCreateInfo.subresourceRange = subrange;
201
202 return device.createImageView(imgViewCreateInfo);
203}
204
205void createImageViews() {
206 assert(swapChainImageViews.empty());
207
208 swapChainImageViews.reserve(swapChainImages.size());
209
210 for (auto &img : swapChainImages) {
211 swapChainImageViews.emplace_back(createImageView(img, swapChainFormat.format));
212 }
213}
214
215void createTextureImageView() {
216 texImgView = createImageView(texImg, vk::Format::eR8G8B8A8Srgb);
217}
218
219void cleanupSwapChain() {
220 for (auto &view : swapChainImageViews) device.destroyImageView(view);
221 swapChainImageViews.clear();
222
223 if (swapChain) {
224 device.destroySwapchainKHR(swapChain);
225 swapChain = nullptr;
226 }
227}
228
229void recreateSwapChain() {
230 int width = 0, height = 0;
231 glfwGetFramebufferSize(window, &width, &height);
232 while (width == 0 || height == 0) {
233 glfwGetFramebufferSize(window, &width, &height);
234 glfwWaitEvents();
235 }
236
237 device.waitIdle();
238
239 vk::SwapchainKHR oldSwapchain = swapChain;
240
241 for (auto &view : swapChainImageViews) device.destroyImageView(view);
242 swapChainImageViews.clear();
243
244 createSwapChain(oldSwapchain);
245 createImageViews();
246
247 if (oldSwapchain) {
248 device.destroySwapchainKHR(oldSwapchain);
249 }
250}
251#pragma endregion
252
253#pragma region cmdBufHelpers
254vk::CommandBuffer beginSingleTimeCommands() {
255 vk::CommandBufferAllocateInfo allocInfo = {};
256 allocInfo.commandPool = cmdPool;
257 allocInfo.level = vk::CommandBufferLevel::ePrimary;
258 allocInfo.commandBufferCount = 1;
259
260 vk::CommandBuffer commandBuffer = std::move(device.allocateCommandBuffers(allocInfo).front());
261
262 vk::CommandBufferBeginInfo beginInfo = {};
263 beginInfo.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit;
264 commandBuffer.begin(beginInfo);
265
266 return std::move(commandBuffer);
267}
268
269void endSingleTimeCommands(vk::CommandBuffer &&commandBuffer) {
270 commandBuffer.end();
271
272 vk::SubmitInfo submitInfo = {};
273 submitInfo.commandBufferCount = 1;
274 submitInfo.pCommandBuffers = &commandBuffer;
275
276 gfxQueue.submit(submitInfo, nullptr);
277 gfxQueue.waitIdle();
278}
279#pragma endregion
280
281#pragma region recordCmdBuf
282void recordCmdBuf(uint32_t imgIdx) {
283 cmdBuf.reset();
284 cmdBuf.begin(beginInfo);
285
286
287 transitionImgLayout(imgIdx,
288 vk::ImageLayout::eUndefined,
289 vk::ImageLayout::eColorAttachmentOptimal,
290 {},
291 vk::AccessFlagBits2::eColorAttachmentWrite,
292 vk::PipelineStageFlagBits2::eColorAttachmentOutput,
293 vk::PipelineStageFlagBits2::eColorAttachmentOutput);
294
295 vk::ClearValue clearColor = vk::ClearColorValue(0.f, 0.f, 0.f, 1.f);
296 vk::RenderingAttachmentInfo attachInfo = {};
297 attachInfo.imageView = swapChainImageViews[imgIdx];
298 attachInfo.imageLayout = vk::ImageLayout::eColorAttachmentOptimal;
299 attachInfo.loadOp = vk::AttachmentLoadOp::eClear;
300 attachInfo.storeOp = vk::AttachmentStoreOp::eStore;
301 attachInfo.clearValue = clearColor;
302
303 vk::RenderingInfo renderingInfo = {};
304 renderingInfo.renderArea = vk::Rect2D{ {0, 0}, swapChainExtent };
305 renderingInfo.layerCount = 1;
306 renderingInfo.colorAttachmentCount = 1;
307 renderingInfo.pColorAttachments = &attachInfo;
308
309 cmdBuf.beginRendering(renderingInfo);
310 cmdBuf.bindPipeline(vk::PipelineBindPoint::eGraphics, gfxPipeline);
311 cmdBuf.bindVertexBuffers(0, vertBuf, { 0 });
312 cmdBuf.bindIndexBuffer(idxBuf, 0, vk::IndexType::eUint16);
313 cmdBuf.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, descriptorSets[frameIdx], nullptr);
314 cmdBuf.setViewport(0, vk::Viewport(0.f, 0.f,
315 static_cast<float>(swapChainExtent.width),
316 static_cast<float>(swapChainExtent.height),
317 0.f, 1.f));
318 cmdBuf.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent));
319 cmdBuf.drawIndexed(static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
320 cmdBuf.endRendering();
321
322 transitionImgLayout(imgIdx,
323 vk::ImageLayout::eColorAttachmentOptimal,
324 vk::ImageLayout::ePresentSrcKHR,
325 vk::AccessFlagBits2::eColorAttachmentWrite,
326 {},
327 vk::PipelineStageFlagBits2::eColorAttachmentOutput,
328 vk::PipelineStageFlagBits2::eBottomOfPipe);
329
330 cmdBuf.end();
331}
332#pragma endregion
333
334#pragma region createBuffer
335std::pair<vk::Buffer, vk::DeviceMemory> createBuffer(vk::DeviceSize size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags props) {
336 vk::BufferCreateInfo bufInfo = {};
337 bufInfo.size = size;
338 bufInfo.usage = usage;
339 bufInfo.sharingMode = vk::SharingMode::eExclusive;
340 vk::Buffer buf = device.createBuffer(bufInfo);
341
342 vk::MemoryRequirements memReq = device.getBufferMemoryRequirements(buf);
343 vk::MemoryAllocateInfo allocInfo = {};
344 allocInfo.allocationSize = memReq.size;
345 allocInfo.memoryTypeIndex = findMemoryType(memReq.memoryTypeBits, props);
346 vk::DeviceMemory alloc = device.allocateMemory(allocInfo);
347 device.bindBufferMemory(buf, alloc, 0);
348
349 return { std::move(buf), std::move(alloc) };
350}
351
352void copyBuffer(vk::Buffer &srcBuf, vk::Buffer &dstBuf, vk::DeviceSize size) {
353 vk::CommandBuffer cmdCopyBuf = beginSingleTimeCommands();
354 cmdCopyBuf.copyBuffer(srcBuf, dstBuf, vk::BufferCopy(0, 0, size));
355 endSingleTimeCommands(std::move(cmdCopyBuf));
356}
357#pragma endregion
358
359#pragma region createImage
360std::pair<vk::Image, vk::DeviceMemory> createImage(uint32_t width, uint32_t height, vk::Format format, vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::MemoryPropertyFlags props) {
361 vk::ImageCreateInfo imgInfo = {};
362 imgInfo.imageType = vk::ImageType::e2D;
363 imgInfo.format = format;
364 imgInfo.extent = { { width, height, 1 } };
365 imgInfo.mipLevels = 1;
366 imgInfo.arrayLayers = 1;
367 imgInfo.samples = vk::SampleCountFlagBits::e1;
368 imgInfo.tiling = tiling;
369 imgInfo.usage = usage;
370 imgInfo.sharingMode = vk::SharingMode::eExclusive;
371
372 vk::Image img = device.createImage(imgInfo);
373
374 vk::MemoryRequirements memReq = device.getImageMemoryRequirements(img);
375 vk::MemoryAllocateInfo allocInfo = {};
376 allocInfo.allocationSize = memReq.size;
377 allocInfo.memoryTypeIndex = findMemoryType(memReq.memoryTypeBits, props);
378
379 vk::DeviceMemory alloc = device.allocateMemory(allocInfo);
380 device.bindImageMemory(img, alloc, 0);
381
382 return { std::move(img), std::move(alloc) };
383}
384
385void copyBufferToImage(vk::CommandBuffer &commandBuffer, const vk::Buffer &buffer, vk::Image &image, uint32_t width, uint32_t height) {
386 vk::ImageSubresourceLayers subresourceLayers = {};
387 subresourceLayers.aspectMask = vk::ImageAspectFlagBits::eColor;
388 subresourceLayers.mipLevel = 0;
389 subresourceLayers.baseArrayLayer = 0;
390 subresourceLayers.layerCount = 1;
391
392 vk::BufferImageCopy region = {};
393 region.bufferOffset = 0;
394 region.bufferRowLength = 0;
395 region.bufferImageHeight = 0;
396 region.imageSubresource = subresourceLayers;
397 region.imageOffset = {{ 0, 0, 0 }};
398 region.imageExtent = {{ width, height, 1 }};
399
400 commandBuffer.copyBufferToImage(buffer, image, vk::ImageLayout::eTransferDstOptimal, region);
401}
402
403void transitionImageLayout(vk::CommandBuffer &commandBuffer, const vk::Image &image, vk::ImageLayout oldLayout, vk::ImageLayout newLayout) {
404 vk::ImageSubresourceRange subresourceRange = {};
405 subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
406 subresourceRange.levelCount = 1;
407 subresourceRange.layerCount = 1;
408
409 vk::ImageMemoryBarrier barrier = {};
410 barrier.oldLayout = oldLayout;
411 barrier.newLayout = newLayout;
412 barrier.srcQueueFamilyIndex = vk::QueueFamilyIgnored;
413 barrier.dstQueueFamilyIndex = vk::QueueFamilyIgnored;
414 barrier.image = image;
415 barrier.subresourceRange = subresourceRange;
416
417 vk::PipelineStageFlags srcStage = {};
418 vk::PipelineStageFlags dstStage = {};
419
420 if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal) {
421 barrier.srcAccessMask = {};
422 barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite;
423
424 srcStage = vk::PipelineStageFlagBits::eTopOfPipe;
425 dstStage = vk::PipelineStageFlagBits::eTransfer;
426 } else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) {
427 barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
428 barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
429
430 srcStage = vk::PipelineStageFlagBits::eTransfer;
431 dstStage = vk::PipelineStageFlagBits::eFragmentShader;
432 } else {
433 assert(false && "レイアウトは未対応です。");
434 return;
435 }
436
437 commandBuffer.pipelineBarrier(srcStage, dstStage, {}, {}, nullptr, barrier);
438}
439#pragma endregion
440
441int main() {
442#pragma region window
443 int winWidth = 800;
444 int winHeight = 600;
445 std::string winName = reinterpret_cast<const char *>(u8"Vulkanレンダー");
446
447 glfwInit();
448 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
449 window = glfwCreateWindow(winWidth, winHeight, winName.c_str(), nullptr, nullptr);
450 glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
451#pragma endregion
452
453#pragma region instance
454 vk::ApplicationInfo applicationInfo = {};
455 applicationInfo.pApplicationName = "Vulkan Render";
456 applicationInfo.applicationVersion = vk::makeVersion(1, 0, 0);
457 applicationInfo.pEngineName = "Small Engine";
458 applicationInfo.engineVersion = vk::makeVersion(1, 0, 0);
459 applicationInfo.apiVersion = vk::ApiVersion14;
460
461 VULKAN_HPP_DEFAULT_DISPATCHER.init();
462
463 vk::InstanceCreateInfo instanceCreateInfo = {};
464 instanceCreateInfo.pApplicationInfo = &applicationInfo;
465
466 uint32_t glfwExtCount = 0;
467 const char **glfwExt = glfwGetRequiredInstanceExtensions(&glfwExtCount);
468 std::vector<const char *> ext(glfwExt, glfwExt + glfwExtCount);
469
470#ifndef NDEBUG
471 ext.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
472
473 std::vector<const char *> reqLayers = { "VK_LAYER_KHRONOS_validation" };
474
475 uint32_t layerCount;
476 auto res1 = vk::enumerateInstanceLayerProperties(&layerCount, nullptr);
477
478 std::vector<vk::LayerProperties> availLayers(layerCount);
479 auto res2 = vk::enumerateInstanceLayerProperties(&layerCount, availLayers.data());
480
481 bool layerFound = std::ranges::any_of(reqLayers, [&](const char *r) {
482 return std::ranges::any_of(availLayers, [&](const auto &p) {
483 return strcmp(r, p.layerName) == 0;
484 });
485 });
486
487 if (!layerFound) {
488 assert(false && "必要なレイヤーを見つけられませんでした。\n");
489 return -1;
490 }
491
492 instanceCreateInfo.enabledLayerCount = static_cast<uint32_t>(reqLayers.size());
493 instanceCreateInfo.ppEnabledLayerNames = reqLayers.data();
494#else
495 instanceCreateInfo.enabledLayerCount = 0;
496#endif
497
498 instanceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(ext.size());
499 instanceCreateInfo.ppEnabledExtensionNames = ext.data();
500
501 vk::Instance instance = vk::createInstance(instanceCreateInfo);
502 VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);
503
504#ifndef NDEBUG
505 vk::DebugUtilsMessageSeverityFlagsEXT severityFlags(vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning
506 | vk::DebugUtilsMessageSeverityFlagBitsEXT::eError);
507 vk::DebugUtilsMessageTypeFlagsEXT messageTypeFlags(vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral
508 | vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance
509 | vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation);
510 vk::DebugUtilsMessengerCreateInfoEXT debugUtilsInfo = {};
511 debugUtilsInfo.messageSeverity = severityFlags;
512 debugUtilsInfo.messageType = messageTypeFlags;
513 debugUtilsInfo.pfnUserCallback = &debugCallback;
514 vk::DebugUtilsMessengerEXT debugMessenger = instance.createDebugUtilsMessengerEXT(debugUtilsInfo);
515#endif
516#pragma endregion
517
518#pragma region surface
519#if defined(_WIN64)
520 vk::Win32SurfaceCreateInfoKHR surfaceCreateInfo = {};
521 surfaceCreateInfo.hinstance = GetModuleHandle(nullptr);
522 surfaceCreateInfo.hwnd = glfwGetWin32Window(window);
523
524 surface = instance.createWin32SurfaceKHR(surfaceCreateInfo);
525#elif defined(__APPLE__)
526 vk::MetalSurfaceCreateInfoEXT surfaceCreateInfo = {};
527 surfaceCreateInfo.pLayer = glfwGetCocoaWindow(window);
528
529 surface = instance.createMetalSurfaceEXT(surfaceCreateInfo);
530#else
531 vk::XcbSurfaceCreateInfoKHR surfaceCreateInfo = {};
532 surfaceCreateInfo.connection = glfwGetX11Display();
533 surfaceCreateInfo.window = glfwGetX11Window(window);
534
535 surface = instance.createXcbSurfaceKHR(surfaceCreateInfo);
536#endif
537#pragma endregion
538
539#pragma region physdevice
540 auto physDevs = instance.enumeratePhysicalDevices();
541 if (physDevs.empty()) {
542 assert(false && "Vulkanを対応しているGPUを見つけられませんでした。");
543 return -1;
544 }
545
546 std::multimap<int, vk::PhysicalDevice> physDevices;
547 for (const auto &dev : physDevs) {
548 auto devProp = dev.getProperties();
549 auto devFeat = dev.getFeatures();
550 uint32_t score = 0;
551
552 if (devProp.deviceType == vk::PhysicalDeviceType::eDiscreteGpu) score += 1000;
553 score += devProp.limits.maxImageDimension2D;
554 if (!devFeat.geometryShader) continue;
555 if (devProp.apiVersion < vk::ApiVersion13) continue;
556 physDevices.insert(std::make_pair(score, dev));
557 }
558
559 if (physDevices.empty()) {
560 assert(false && "利用可能なGPUを見つけられませんでした。");
561 return -1;
562 }
563
564 physicalDevice = physDevices.rbegin()->second;
565
566 auto queueFamilies = physicalDevice.getQueueFamilyProperties();
567 bool supportsGfx = std::ranges::any_of(queueFamilies, [](auto const &q) {
568 return !!(q.queueFlags & vk::QueueFlagBits::eGraphics);
569 });
570
571 std::vector<const char *> reqDevExt = { vk::KHRSwapchainExtensionName };
572 auto availDevExt = physicalDevice.enumerateDeviceExtensionProperties();
573 bool supportAllExt = std::ranges::all_of(reqDevExt, [&availDevExt](auto const &reqDevExt) {
574 return std::ranges::any_of(availDevExt, [reqDevExt](auto const &e) {
575 return strcmp(e.extensionName, reqDevExt) == 0;;
576 });
577 });
578
579 auto features = physicalDevice.template getFeatures2<vk::PhysicalDeviceFeatures2,
580 vk::PhysicalDeviceVulkan11Features,
581 vk::PhysicalDeviceVulkan13Features,
582 vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>();
583 bool supportReqFeature = features.template get<vk::PhysicalDeviceFeatures2>().features.samplerAnisotropy
584 && features.template get<vk::PhysicalDeviceVulkan13Features>().dynamicRendering
585 && features.template get<vk::PhysicalDeviceVulkan13Features>().synchronization2
586 && features.template get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>().extendedDynamicState;
587
588 if (!supportAllExt || !supportsGfx || !supportReqFeature) {
589 assert(false && "利用可能なGPUを見つけられませんでした。");
590 return -1;
591 }
592#pragma endregion
593
594#pragma region logicdevice
595 std::vector<vk::QueueFamilyProperties> queueFamProps = physicalDevice.getQueueFamilyProperties();
596 auto gfxQueueFamProp = std::ranges::find_if(queueFamProps, [](auto const &q) {
597 return (q.queueFlags & vk::QueueFlagBits::eGraphics) != static_cast<vk::QueueFlags>(0);
598 });
599
600 uint32_t queueIdx = ~0;
601 for (uint32_t q = 0; q < queueFamProps.size(); ++q) {
602 if ((queueFamProps[q].queueFlags & vk::QueueFlagBits::eGraphics)
603 && physicalDevice.getSurfaceSupportKHR(q, surface)) {
604 queueIdx = q;
605 break;
606 }
607 }
608
609 if (queueIdx == ~0) {
610 assert(false && "グラフィックと表示塞翁しているキューを見つけられませんでした。");
611 return -1;
612 }
613
614 auto gfxIdx = static_cast<uint32_t>(std::distance(queueFamProps.begin(), gfxQueueFamProp));
615 float queuePriority = .5f;
616
617 vk::PhysicalDeviceFeatures2 baseFeatures{};
618 baseFeatures.features = {{ .samplerAnisotropy = true }};
619 vk::PhysicalDeviceVulkan11Features features11{};
620 features11.shaderDrawParameters = true;
621 vk::PhysicalDeviceVulkan13Features features13{};
622 features13.dynamicRendering = true;
623 features13.synchronization2 = true;
624
625 vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT extDynState{};
626 extDynState.extendedDynamicState = true;
627
628 vk::StructureChain<vk::PhysicalDeviceFeatures2,
629 vk::PhysicalDeviceVulkan11Features,
630 vk::PhysicalDeviceVulkan13Features,
631 vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT> featureChain = {
632 baseFeatures,
633 features11,
634 features13,
635 extDynState,
636 };
637
638 vk::DeviceQueueCreateInfo devQueueCreateInfo = {};
639 devQueueCreateInfo.queueFamilyIndex = gfxIdx;
640 devQueueCreateInfo.queueCount = 1;
641 devQueueCreateInfo.pQueuePriorities = &queuePriority;
642
643 vk::DeviceCreateInfo devCreateInfo = {};
644 devCreateInfo.pNext = &featureChain.get<vk::PhysicalDeviceFeatures2>();
645 devCreateInfo.queueCreateInfoCount = 1;
646 devCreateInfo.pQueueCreateInfos = &devQueueCreateInfo;
647 devCreateInfo.enabledExtensionCount = static_cast<uint32_t>(reqDevExt.size());
648 devCreateInfo.ppEnabledExtensionNames = reqDevExt.data();
649
650 device = physicalDevice.createDevice(devCreateInfo);
651 VULKAN_HPP_DEFAULT_DISPATCHER.init(device);
652 gfxQueue = device.getQueue(gfxIdx, 0);
653#pragma endregion
654
655#pragma region swapchain
656 createSwapChain();
657#pragma endregion
658
659#pragma region imageviews
660 createImageViews();
661#pragma endregion
662
663#pragma region descriptorSetLayout
664 std::array<vk::DescriptorSetLayoutBinding, 2> bindings;
665 {
666 vk::DescriptorSetLayoutBinding uboLayoutBinding = {};
667 uboLayoutBinding.binding = 0;
668 uboLayoutBinding.descriptorType = vk::DescriptorType::eUniformBuffer;
669 uboLayoutBinding.descriptorCount = 1;
670 uboLayoutBinding.stageFlags = vk::ShaderStageFlagBits::eVertex;
671 bindings[0] = uboLayoutBinding;
672 }
673 {
674 vk::DescriptorSetLayoutBinding uboLayoutBinding = {};
675 uboLayoutBinding.binding = 1;
676 uboLayoutBinding.descriptorType = vk::DescriptorType::eCombinedImageSampler;
677 uboLayoutBinding.descriptorCount = 1;
678 uboLayoutBinding.stageFlags = vk::ShaderStageFlagBits::eFragment;
679 bindings[1] = uboLayoutBinding;
680 }
681
682 vk::DescriptorSetLayoutCreateInfo layoutInfo = {};
683 layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
684 layoutInfo.pBindings = bindings.data();
685
686 descriptorSetLayout = device.createDescriptorSetLayout(layoutInfo);
687#pragma endregion
688
689#pragma region gfxPipeline
690 Shaders shader(&device);
691 std::vector<vk::PipelineShaderStageCreateInfo> shaderStages = shader.GetShaderStages();
692#pragma endregion
693
694#pragma region fixedFunctions
695 std::vector<vk::DynamicState> dynStates = {
696 vk::DynamicState::eViewport,
697 vk::DynamicState::eScissor,
698 };
699
700 vk::PipelineVertexInputStateCreateInfo vertexInputInfo = shader.GetVertexInput();
701
702 vk::PipelineInputAssemblyStateCreateInfo inputAss = {};
703 inputAss.topology = vk::PrimitiveTopology::eTriangleList;
704
705 vk::Viewport viewport = {};
706 viewport.x = 0.f;
707 viewport.y = 0.f;
708 viewport.width = static_cast<float>(swapChainExtent.width);
709 viewport.height = static_cast<float>(swapChainExtent.height);
710 viewport.minDepth = 0.f;
711 viewport.maxDepth = 1.f;
712
713 vk::Rect2D scissor = {};
714 scissor.offset = vk::Offset2D{ 0, 0 };
715 scissor.extent = swapChainExtent;
716
717 vk::PipelineDynamicStateCreateInfo dynState = {};
718 dynState.dynamicStateCount = static_cast<uint32_t>(dynStates.size());
719 dynState.pDynamicStates = dynStates.data();
720
721 vk::PipelineViewportStateCreateInfo viewportState = {};
722 viewportState.viewportCount = 1;
723 viewportState.pViewports = &viewport;
724 viewportState.scissorCount = 1;
725 viewportState.pScissors = &scissor;
726
727 vk::PipelineRasterizationStateCreateInfo rasterizer = {};
728 rasterizer.depthClampEnable = vk::False;
729 rasterizer.rasterizerDiscardEnable = vk::False;
730 rasterizer.polygonMode = vk::PolygonMode::eFill;
731 rasterizer.cullMode = vk::CullModeFlagBits::eBack;
732 rasterizer.frontFace = vk::FrontFace::eCounterClockwise;
733 rasterizer.depthBiasEnable = vk::False;
734 rasterizer.lineWidth = 1.f;
735
736 vk::PipelineMultisampleStateCreateInfo multisampling = {};
737 multisampling.rasterizationSamples = vk::SampleCountFlagBits::e1;
738 multisampling.sampleShadingEnable = vk::False;
739
740 vk::PipelineColorBlendAttachmentState colorBlendAttachment = {};
741 colorBlendAttachment.blendEnable = vk::True;
742 colorBlendAttachment.srcColorBlendFactor = vk::BlendFactor::eSrcAlpha;
743 colorBlendAttachment.dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha;
744 colorBlendAttachment.colorBlendOp = vk::BlendOp::eAdd;
745 colorBlendAttachment.srcAlphaBlendFactor = vk::BlendFactor::eOne;
746 colorBlendAttachment.dstAlphaBlendFactor = vk::BlendFactor::eZero;
747 colorBlendAttachment.alphaBlendOp = vk::BlendOp::eAdd;
748 colorBlendAttachment.colorWriteMask = vk::ColorComponentFlagBits::eR
749 | vk::ColorComponentFlagBits::eG
750 | vk::ColorComponentFlagBits::eB
751 | vk::ColorComponentFlagBits::eA;
752
753 vk::PipelineColorBlendStateCreateInfo colorBlending = {};
754 colorBlending.logicOpEnable = vk::False;
755 colorBlending.logicOp = vk::LogicOp::eCopy;
756 colorBlending.attachmentCount = 1;
757 colorBlending.pAttachments = &colorBlendAttachment;
758
759 vk::PipelineLayoutCreateInfo pipelineLayoutInfo = {};
760 pipelineLayoutInfo.setLayoutCount = 1;
761 pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
762 pipelineLayoutInfo.pushConstantRangeCount = 0;
763
764 pipelineLayout = device.createPipelineLayout(pipelineLayoutInfo);
765#pragma endregion
766
767#pragma region pipelineRendering
768 vk::PipelineRenderingCreateInfo pipelineRenderingCreateInfo = {};
769 pipelineRenderingCreateInfo.colorAttachmentCount = 1;
770 pipelineRenderingCreateInfo.pColorAttachmentFormats = &swapChainFormat.format;
771
772 vk::GraphicsPipelineCreateInfo pipelineInfo = {};
773 pipelineInfo.stageCount = 2;
774 pipelineInfo.pStages = shaderStages.data();
775 pipelineInfo.pVertexInputState = &vertexInputInfo;
776 pipelineInfo.pInputAssemblyState = &inputAss;
777 pipelineInfo.pViewportState = &viewportState;
778 pipelineInfo.pRasterizationState = &rasterizer;
779 pipelineInfo.pMultisampleState = &multisampling;
780 pipelineInfo.pColorBlendState = &colorBlending;
781 pipelineInfo.pDynamicState = &dynState;
782 pipelineInfo.layout = pipelineLayout;
783 pipelineInfo.pNext = &pipelineRenderingCreateInfo;
784 pipelineInfo.renderPass = nullptr;
785
786 auto [result, pipeline] = device.createGraphicsPipeline(nullptr, pipelineInfo);
787 if (result != vk::Result::eSuccess) {
788 assert(false && "グラフィックパイプラインの設置にしっぱい。");
789 return -1;
790 }
791
792 gfxPipeline = pipeline;
793#pragma endregion
794
795#pragma region commandPool
796 vk::CommandPoolCreateInfo poolInfo = {};
797 poolInfo.flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer;
798 poolInfo.queueFamilyIndex = queueIdx;
799
800 cmdPool = device.createCommandPool(poolInfo);
801#pragma endregion
802
803#pragma region textureImage
804 {
805 int texWidth, texHeight, texChan;
806 stbi_uc *pixels = stbi_load("ass/texture/techsuwa.png", &texWidth, &texHeight, &texChan, STBI_rgb_alpha);
807 vk::DeviceSize imgSize = texWidth * texHeight * 4;
808 vk::MemoryPropertyFlags flags = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent;
809
810 if (!pixels) {
811 assert(false && "テキスチャーの読み込みに失敗。");
812 return -1;
813 }
814
815 auto [stagingBuf, stagingBufMem] = createBuffer(imgSize, vk::BufferUsageFlagBits::eTransferSrc, flags);
816
817 void *dataStaging = device.mapMemory(stagingBufMem, 0, imgSize);
818 memcpy(dataStaging, pixels, imgSize);
819 device.unmapMemory(stagingBufMem);
820
821 stbi_image_free(pixels);
822
823 vk::Format fmt = vk::Format::eR8G8B8A8Srgb;
824 vk::ImageTiling tile = vk::ImageTiling::eOptimal;
825 vk::ImageUsageFlags usa = vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled;
826 vk::MemoryPropertyFlags prop = vk::MemoryPropertyFlagBits::eDeviceLocal;
827 std::tie(texImg, texImgMem) = createImage(texWidth, texHeight, fmt, tile, usa, prop);
828
829 vk::CommandBuffer commandBuf = beginSingleTimeCommands();
830 transitionImageLayout(commandBuf, texImg, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal);
831 copyBufferToImage(commandBuf, stagingBuf, texImg, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight));
832 transitionImageLayout(commandBuf, texImg, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal);
833 endSingleTimeCommands(std::move(commandBuf));
834 if (stagingBuf) device.destroyBuffer(stagingBuf);
835 if (stagingBufMem) device.freeMemory(stagingBufMem);
836 }
837
838 createTextureImageView();
839
840 {
841 vk::PhysicalDeviceProperties props = physicalDevice.getProperties();
842 vk::SamplerCreateInfo samplerInfo = {};
843 samplerInfo.magFilter = vk::Filter::eLinear;
844 samplerInfo.minFilter = vk::Filter::eLinear;
845 samplerInfo.mipmapMode = vk::SamplerMipmapMode::eLinear;
846 samplerInfo.addressModeU = vk::SamplerAddressMode::eRepeat;
847 samplerInfo.addressModeV = vk::SamplerAddressMode::eRepeat;
848 samplerInfo.addressModeW = vk::SamplerAddressMode::eRepeat;
849 samplerInfo.anisotropyEnable = vk::True;
850 samplerInfo.maxAnisotropy = props.limits.maxSamplerAnisotropy;
851 samplerInfo.compareEnable = vk::False;
852 samplerInfo.compareOp = vk::CompareOp::eAlways;
853 samplerInfo.borderColor = vk::BorderColor::eIntOpaqueBlack;
854 samplerInfo.unnormalizedCoordinates = vk::False;
855 samplerInfo.mipmapMode = vk::SamplerMipmapMode::eLinear;
856 samplerInfo.mipLodBias = 0.f;
857 samplerInfo.minLod = 0.f;
858 samplerInfo.maxLod = 0.f;
859
860 texSampler = device.createSampler(samplerInfo);
861 }
862#pragma endregion
863
864#pragma region vertexBuffer
865 {
866 vk::DeviceSize bufSize = sizeof(vertices[0]) * vertices.size();
867 vk::MemoryPropertyFlags flags = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent;
868 auto [stagingBuf, stagingBufMem] = createBuffer(bufSize, vk::BufferUsageFlagBits::eTransferSrc, flags);
869
870 void *dataStaging = device.mapMemory(stagingBufMem, 0, bufSize);
871 memcpy(dataStaging, vertices.data(), bufSize);
872 device.unmapMemory(stagingBufMem);
873
874 std::tie(vertBuf, vertBufMem) = createBuffer(bufSize, vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eTransferDst, vk::MemoryPropertyFlagBits::eDeviceLocal);
875 copyBuffer(stagingBuf, vertBuf, bufSize);
876 if (stagingBuf) device.destroyBuffer(stagingBuf);
877 if (stagingBufMem) device.freeMemory(stagingBufMem);
878 }
879#pragma endregion
880
881#pragma region indexBuffer
882 {
883 vk::DeviceSize bufSize = sizeof(indices[0]) * indices.size();
884 vk::MemoryPropertyFlags flags = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent;
885 auto [stagingBuf, stagingBufMem] = createBuffer(bufSize, vk::BufferUsageFlagBits::eTransferSrc, flags);
886
887 void *dataStaging = device.mapMemory(stagingBufMem, 0, bufSize);
888 memcpy(dataStaging, indices.data(), (size_t)bufSize);
889 device.unmapMemory(stagingBufMem);
890
891 std::tie(idxBuf, idxBufMem) = createBuffer(bufSize, vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eTransferDst, vk::MemoryPropertyFlagBits::eDeviceLocal);
892 copyBuffer(stagingBuf, idxBuf, bufSize);
893 if (stagingBuf) device.destroyBuffer(stagingBuf);
894 if (stagingBufMem) device.freeMemory(stagingBufMem);
895 }
896#pragma endregion
897
898#pragma region uniformBuffers
899 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
900 vk::DeviceSize bufSize = sizeof(UniformBufferObject);
901 vk::MemoryPropertyFlags flags = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent;
902 auto [buf, bufMem] = createBuffer(bufSize, vk::BufferUsageFlagBits::eUniformBuffer, flags);
903 uniformBufs.emplace_back(std::move(buf));
904 uniformBufsMem.emplace_back(std::move(bufMem));
905 uniformBufsMapped.emplace_back(device.mapMemory(uniformBufsMem.back(), 0, bufSize));
906 }
907#pragma endregion
908
909#pragma region descriptorPool
910 std::array<vk::DescriptorPoolSize, 2> descPoolSize;
911 {
912 vk::DescriptorPoolSize ps = {};
913 ps.type = vk::DescriptorType::eUniformBuffer;
914 ps.descriptorCount = MAX_FRAMES_IN_FLIGHT;
915 descPoolSize[0] = ps;
916 }
917 {
918 vk::DescriptorPoolSize ps = {};
919 ps.type = vk::DescriptorType::eCombinedImageSampler;
920 ps.descriptorCount = MAX_FRAMES_IN_FLIGHT;
921 descPoolSize[1] = ps;
922 }
923
924 vk::DescriptorPoolCreateInfo descPoolInfo = {};
925 descPoolInfo.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet;
926 descPoolInfo.maxSets = MAX_FRAMES_IN_FLIGHT;
927 descPoolInfo.poolSizeCount = static_cast<uint32_t>(descPoolSize.size());
928 descPoolInfo.pPoolSizes = descPoolSize.data();
929
930 descriptorPool = device.createDescriptorPool(descPoolInfo);
931#pragma endregion
932
933#pragma region descriptorSets
934 std::vector<vk::DescriptorSetLayout> layouts{ MAX_FRAMES_IN_FLIGHT, descriptorSetLayout };
935 vk::DescriptorSetAllocateInfo descAllocInfo = {};
936 descAllocInfo.descriptorPool = descriptorPool;
937 descAllocInfo.descriptorSetCount = static_cast<uint32_t>(layouts.size());
938 descAllocInfo.pSetLayouts = layouts.data();
939
940 descriptorSets = device.allocateDescriptorSets(descAllocInfo);
941
942 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
943 vk::DescriptorBufferInfo descBufInfo = {};
944 descBufInfo.buffer = uniformBufs[i];
945 descBufInfo.offset = 0;
946 descBufInfo.range = sizeof(UniformBufferObject);
947
948 vk::DescriptorImageInfo imgInfo = {};
949 imgInfo.sampler = texSampler;
950 imgInfo.imageView = texImgView;
951 imgInfo.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
952
953 std::array<vk::WriteDescriptorSet, 2> descWrites;
954 {
955 vk::WriteDescriptorSet descWrite = {};
956 descWrite.dstSet = descriptorSets[i];
957 descWrite.dstBinding = 0;
958 descWrite.dstArrayElement = 0;
959 descWrite.descriptorCount = 1;
960 descWrite.descriptorType = vk::DescriptorType::eUniformBuffer;
961 descWrite.pBufferInfo = &descBufInfo;
962 descWrites[0] = descWrite;
963 }
964 {
965 vk::WriteDescriptorSet descWrite = {};
966 descWrite.dstSet = descriptorSets[i];
967 descWrite.dstBinding = 1;
968 descWrite.dstArrayElement = 0;
969 descWrite.descriptorCount = 1;
970 descWrite.descriptorType = vk::DescriptorType::eCombinedImageSampler;
971 descWrite.pImageInfo = &imgInfo;
972 descWrites[1] = descWrite;
973 }
974
975 device.updateDescriptorSets(descWrites, {});
976 }
977#pragma endregion
978
979#pragma region commandbuffers
980 vk::CommandBufferAllocateInfo allocInfo = {};
981 allocInfo.commandPool = cmdPool;
982 allocInfo.level = vk::CommandBufferLevel::ePrimary;
983 allocInfo.commandBufferCount = MAX_FRAMES_IN_FLIGHT;
984
985 std::vector<vk::CommandBuffer> cmdBufs = device.allocateCommandBuffers(allocInfo);
986 cmdBuf = cmdBufs.front();
987
988 beginInfo.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit;
989
990 uint32_t imgIdx = 0;
991 recordCmdBuf(imgIdx);
992#pragma endregion
993
994#pragma region syncObjects
995 std::vector<vk::Semaphore> presentCompleteSemaphores;
996 std::vector<vk::Semaphore> renderFinishedSemaphores;
997 std::vector<vk::Fence> inFlightFences;
998 assert(presentCompleteSemaphores.empty() && renderFinishedSemaphores.empty() && inFlightFences.empty());
999
1000 for (size_t i = 0; i < swapChainImages.size(); ++i) {
1001 renderFinishedSemaphores.emplace_back(device.createSemaphore(vk::SemaphoreCreateInfo()));
1002 }
1003
1004 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
1005 presentCompleteSemaphores.emplace_back(device.createSemaphore(vk::SemaphoreCreateInfo()));
1006
1007 vk::FenceCreateInfo fenceInfo = {};
1008 fenceInfo.flags = vk::FenceCreateFlagBits::eSignaled;
1009 inFlightFences.emplace_back(device.createFence(fenceInfo));
1010 }
1011#pragma endregion
1012
1013 while (!glfwWindowShouldClose(window)) {
1014 if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS) {
1015 glfwSetWindowShouldClose(window, true);
1016 }
1017
1018 glfwPollEvents();
1019
1020#pragma region drawFrame
1021 if (framebufferResized) {
1022 recreateSwapChain();
1023 framebufferResized = false;
1024 }
1025
1026 auto fenceResult = device.waitForFences(inFlightFences[frameIdx], vk::True, UINT64_MAX);
1027 if (fenceResult != vk::Result::eSuccess) {
1028 assert(false && "フェンスまで待つに失敗。");
1029 break;
1030 }
1031
1032 device.resetFences(inFlightFences[frameIdx]);
1033 auto [acquireRes, imgIdx] = device.acquireNextImageKHR(swapChain, UINT64_MAX, presentCompleteSemaphores[frameIdx], nullptr);
1034
1035 if (acquireRes == vk::Result::eErrorOutOfDateKHR) {
1036 recreateSwapChain();
1037 framebufferResized = false;
1038 } else if (acquireRes != vk::Result::eSuccess && acquireRes != vk::Result::eSuboptimalKHR) {
1039 assert((acquireRes == vk::Result::eTimeout || acquireRes == vk::Result::eNotReady) && "次の画像の受け取りに失敗。");
1040 break;
1041 }
1042
1043 recordCmdBuf(imgIdx);
1044
1045 vk::PipelineStageFlags waitStage = vk::PipelineStageFlagBits::eColorAttachmentOutput;
1046
1047#pragma region updateUniformBuffer
1048 static auto startTime = std::chrono::high_resolution_clock::now();
1049 auto curTime = std::chrono::high_resolution_clock::now();
1050 float time = std::chrono::duration<float, std::chrono::seconds::period>(curTime - startTime).count();
1051
1052 UniformBufferObject ubo = {};
1053 ubo.model = rotate(glm::mat4(1.f), time * glm::radians(90.f), glm::vec3(0.f, 0.f, 1.f));
1054 ubo.view = lookAt(glm::vec3(2.f, 2.f, 2.f), glm::vec3(0.f, 0.f, 0.f), glm::vec3(0.f, 0.f, 1.f));
1055 ubo.proj = glm::perspective(glm::radians(45.f), static_cast<float>(swapChainExtent.width) / static_cast<float>(swapChainExtent.height), .1f, 10.f);
1056 ubo.proj[1][1] *= -1; // -Y軸
1057 memcpy(uniformBufsMapped[frameIdx], &ubo, sizeof(ubo));
1058#pragma endregion
1059
1060 vk::SubmitInfo submitInfo = {};
1061 submitInfo.waitSemaphoreCount = 1;
1062 submitInfo.pWaitSemaphores = &presentCompleteSemaphores[frameIdx];
1063 submitInfo.pWaitDstStageMask = &waitStage;
1064 submitInfo.commandBufferCount = 1;
1065 submitInfo.pCommandBuffers = &cmdBuf;
1066 submitInfo.signalSemaphoreCount = 1;
1067 submitInfo.pSignalSemaphores = &renderFinishedSemaphores[frameIdx];
1068
1069 gfxQueue.submit(submitInfo, inFlightFences[frameIdx]);
1070
1071 vk::PresentInfoKHR presentInfo = {};
1072 presentInfo.waitSemaphoreCount = 1;
1073 presentInfo.pWaitSemaphores = &renderFinishedSemaphores[frameIdx];
1074 presentInfo.swapchainCount = 1;
1075 presentInfo.pSwapchains = &swapChain;
1076 presentInfo.pImageIndices = &imgIdx;
1077
1078 vk::Result presentRes = gfxQueue.presentKHR(presentInfo);
1079 if (presentRes == vk::Result::eSuboptimalKHR || presentRes == vk::Result::eErrorOutOfDateKHR || framebufferResized) {
1080 recreateSwapChain();
1081 framebufferResized = false;
1082 } else {
1083 assert(presentRes == vk::Result::eSuccess);
1084 }
1085
1086 frameIdx = (frameIdx + 1) % MAX_FRAMES_IN_FLIGHT;
1087#pragma endregion
1088
1089 device.waitIdle();
1090 }
1091
1092#pragma region destroy
1093 if (device) device.waitIdle();
1094 if (cmdPool) device.destroyCommandPool(cmdPool);
1095 if (idxBuf) device.destroyBuffer(idxBuf);
1096 if (idxBufMem) device.freeMemory(idxBufMem);
1097 if (vertBuf) device.destroyBuffer(vertBuf);
1098 if (vertBufMem) device.freeMemory(vertBufMem);
1099 for (const auto &it : uniformBufs) device.destroyBuffer(it);
1100 for (const auto &it : uniformBufsMem) device.freeMemory(it);
1101 if (texSampler) device.destroySampler(texSampler);
1102 if (texImgView) device.destroyImageView(texImgView);
1103 if (texImg) device.destroyImage(texImg);
1104 if (texImgMem) device.freeMemory(texImgMem);
1105 if (gfxPipeline) device.destroyPipeline(gfxPipeline);
1106 if (pipelineLayout) device.destroyPipelineLayout(pipelineLayout);
1107 shader.Finalize();
1108 if (descriptorSetLayout) device.destroyDescriptorSetLayout(descriptorSetLayout);
1109 if (descriptorPool) device.destroyDescriptorPool(descriptorPool);
1110 cleanupSwapChain();
1111 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) device.destroySemaphore(presentCompleteSemaphores[i]);
1112 for (size_t i = 0; i < swapChainImages.size(); ++i) device.destroySemaphore(renderFinishedSemaphores[i]);
1113 for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) device.destroyFence(inFlightFences[i]);
1114 if (device) device.destroy();
1115#ifndef NDEBUG
1116 if (debugMessenger) instance.destroyDebugUtilsMessengerEXT(debugMessenger);
1117#endif
1118 if (surface) instance.destroySurfaceKHR(surface);
1119 if (instance) instance.destroy();
1120
1121 if (window) {
1122 glfwDestroyWindow(window);
1123 glfwTerminate();
1124 }
1125
1126 //Sleep(9 * 1000000);
1127#pragma endregion
1128
1129 return 0;
1130}