VulkanWrapper.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. #include "core/VulkanWrapper.hpp"
  2. #include <core/File.hpp>
  3. #include <core/UniquePointer.hpp>
  4. #include "GLFW.hpp"
  5. #include "core/VulkanBase.hpp"
  6. namespace Vulkan = Core::Vulkan;
  7. using Vulkan::CommandBuffer;
  8. using Vulkan::Queue;
  9. using Vulkan::SwapchainImages;
  10. #define WRAPPER_DESTRUCT(Type, ...) \
  11. using Core::Vulkan::Type; \
  12. Type::~Type() { \
  13. if(device != VK_NULL_HANDLE) { \
  14. vkDestroy##Type##__VA_ARGS__(device, handle, nullptr); \
  15. } \
  16. }
  17. WRAPPER_DESTRUCT(ImageView)
  18. WRAPPER_DESTRUCT(Framebuffer)
  19. WRAPPER_DESTRUCT(Semaphore)
  20. WRAPPER_DESTRUCT(Fence)
  21. WRAPPER_DESTRUCT(Swapchain, KHR)
  22. WRAPPER_DESTRUCT(ShaderModule)
  23. WRAPPER_DESTRUCT(PipelineLayout)
  24. WRAPPER_DESTRUCT(Pipeline)
  25. WRAPPER_DESTRUCT(CommandPool)
  26. WRAPPER_DESTRUCT(RenderPass)
  27. bool ImageView::init(VkDevice d, VkImage image, VkFormat format) {
  28. VkImageViewCreateInfo info = {
  29. .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
  30. .image = image,
  31. .viewType = VK_IMAGE_VIEW_TYPE_2D,
  32. .format = format,
  33. .subresourceRange = {
  34. .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
  35. .baseMipLevel = 0,
  36. .levelCount = 1,
  37. .baseArrayLayer = 0,
  38. .layerCount = 1}};
  39. VK_CHECK_TRUE(vkCreateImageView(d, &info, nullptr, &handle));
  40. device = d;
  41. return false;
  42. }
  43. bool Framebuffer::init(
  44. const ImageView& iv, VkRenderPass rp, u32 width, u32 height) {
  45. VkFramebufferCreateInfo info = {
  46. .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
  47. .renderPass = rp,
  48. .attachmentCount = 1,
  49. .pAttachments = iv,
  50. .width = width,
  51. .height = height,
  52. .layers = 1};
  53. VK_CHECK_TRUE(vkCreateFramebuffer(iv.device, &info, nullptr, &handle));
  54. device = iv.device;
  55. return false;
  56. }
  57. bool Semaphore::init(VkDevice d) {
  58. VkSemaphoreCreateInfo info = {
  59. .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
  60. VK_CHECK_TRUE(vkCreateSemaphore(d, &info, nullptr, &handle));
  61. device = d;
  62. return false;
  63. }
  64. bool Fence::init(VkDevice d) {
  65. VkFenceCreateInfo info = {
  66. .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
  67. .flags = VK_FENCE_CREATE_SIGNALED_BIT};
  68. VK_CHECK_TRUE(vkCreateFence(d, &info, nullptr, &handle));
  69. device = d;
  70. return false;
  71. }
  72. void Fence::reset() {
  73. VK_CHECK_VOID(vkResetFences(device, 1, &handle));
  74. }
  75. void Fence::waitFor(u64 timeout) {
  76. VK_CHECK_VOID(vkWaitForFences(device, 1, &handle, true, timeout));
  77. }
  78. static u32 getSwapImageCount(const VkSurfaceCapabilitiesKHR* caps) {
  79. u32 c = caps->minImageCount + 1;
  80. // according to VkSurfaceCapabilitiesKHR doc:
  81. // maxImageCount is 0 when there is no strict limit
  82. if(caps->maxImageCount != 0) {
  83. return Core::min(c, caps->maxImageCount);
  84. }
  85. return c;
  86. }
  87. bool Swapchain::init(Data& d) {
  88. VkSurfaceCapabilitiesKHR caps = {0};
  89. if(d.base.getSurfaceCapabilities(caps)) {
  90. return true;
  91. }
  92. VkSwapchainCreateInfoKHR ci = {
  93. .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
  94. .surface = d.base,
  95. .minImageCount = getSwapImageCount(&caps),
  96. .imageFormat = d.surfaceFormat.format,
  97. .imageColorSpace = d.surfaceFormat.colorSpace,
  98. .imageExtent = d.size,
  99. .imageArrayLayers = 1,
  100. .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
  101. .imageSharingMode = d.sharingMode,
  102. .queueFamilyIndexCount = static_cast<u32>(d.queueFamilies.getLength()),
  103. .pQueueFamilyIndices = &d.queueFamilies[0],
  104. .preTransform = caps.currentTransform,
  105. .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
  106. .presentMode = d.presentMode,
  107. .clipped = VK_TRUE,
  108. .oldSwapchain = VK_NULL_HANDLE};
  109. VK_CHECK_TRUE(vkCreateSwapchainKHR(d.base, &ci, nullptr, &handle));
  110. device = d.base;
  111. return false;
  112. }
  113. bool Swapchain::nextImage(u32& imageIndex, Semaphore& s, u64 timeout) {
  114. VK_CHECK_TRUE(vkAcquireNextImageKHR(
  115. device, handle, timeout, s, VK_NULL_HANDLE, &imageIndex));
  116. return false;
  117. }
  118. bool ShaderModule::init(VkDevice d, const char* path) {
  119. List<char> f;
  120. if(Core::readFile(f, path)) {
  121. return true;
  122. }
  123. size_t l = f.getLength() - 1;
  124. if((l % 4) != 0) {
  125. VK_REPORT_ERROR("Shader size is not a multiple of 4");
  126. return true;
  127. }
  128. VkShaderModuleCreateInfo info = {
  129. .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
  130. .codeSize = l,
  131. .pCode = reinterpret_cast<u32*>(static_cast<void*>(&f[0]))};
  132. VK_CHECK_TRUE(vkCreateShaderModule(d, &info, nullptr, &handle));
  133. device = d;
  134. return false;
  135. }
  136. bool PipelineLayout::init(VkDevice d) {
  137. VkPipelineLayoutCreateInfo info = {
  138. .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
  139. VK_CHECK_TRUE(vkCreatePipelineLayout(d, &info, nullptr, &handle));
  140. device = d;
  141. return false;
  142. }
  143. bool SwapchainImages::init(const Swapchain& s, VkFormat format) {
  144. u32 c = 0;
  145. VK_CHECK_TRUE(vkGetSwapchainImagesKHR(s.device, s.handle, &c, nullptr));
  146. images.resize(c);
  147. imageViews.resize(c);
  148. VK_CHECK_TRUE(vkGetSwapchainImagesKHR(s.device, s.handle, &c, &images[0]));
  149. for(u32 x = 0; x < c; x++) {
  150. if(imageViews[x].init(s.device, images[x], format)) {
  151. return true;
  152. }
  153. }
  154. return false;
  155. }
  156. bool RenderPass::init(VkDevice d, VkFormat format) {
  157. VkAttachmentDescription c = {
  158. .format = format,
  159. .samples = VK_SAMPLE_COUNT_1_BIT,
  160. .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
  161. .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
  162. .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
  163. .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
  164. .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
  165. .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR};
  166. VkAttachmentReference ca = {
  167. .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
  168. VkSubpassDescription subpass = {
  169. .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
  170. .colorAttachmentCount = 1,
  171. .pColorAttachments = &ca};
  172. VkSubpassDependency dependency = {
  173. .srcSubpass = VK_SUBPASS_EXTERNAL,
  174. .dstSubpass = 0,
  175. .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
  176. .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
  177. .srcAccessMask = 0,
  178. .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
  179. };
  180. VkRenderPassCreateInfo info = {
  181. .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
  182. .attachmentCount = 1,
  183. .pAttachments = &c,
  184. .subpassCount = 1,
  185. .pSubpasses = &subpass,
  186. .dependencyCount = 1,
  187. .pDependencies = &dependency};
  188. VK_CHECK_TRUE(vkCreateRenderPass(d, &info, nullptr, &handle));
  189. device = d;
  190. return false;
  191. }
  192. Pipeline::Pipeline() : viewport{.maxDepth = 1.0f}, scissor{} {
  193. }
  194. void Pipeline::updateSize(u32 width, u32 height) {
  195. viewport.width = static_cast<float>(width);
  196. viewport.height = static_cast<float>(height);
  197. scissor.extent.width = width;
  198. scissor.extent.height = height;
  199. }
  200. bool Pipeline::init(PipelineLayout& pl, RenderPass& rp) {
  201. ShaderModule vertexShaderModule;
  202. ShaderModule fragmentShaderModule;
  203. if(vertexShaderModule.init(pl.device, "shaders/vertex.spv") ||
  204. fragmentShaderModule.init(pl.device, "shaders/fragment.spv")) {
  205. return true;
  206. }
  207. VkPipelineShaderStageCreateInfo stages[2] = {
  208. {.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
  209. .stage = VK_SHADER_STAGE_VERTEX_BIT,
  210. .module = vertexShaderModule,
  211. .pName = "main"},
  212. {.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
  213. .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
  214. .module = fragmentShaderModule,
  215. .pName = "main"}};
  216. VkPipelineVertexInputStateCreateInfo vertexInputState = {
  217. .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO};
  218. VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {
  219. .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
  220. .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
  221. .primitiveRestartEnable = false};
  222. VkPipelineViewportStateCreateInfo viewportState = {
  223. .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
  224. .viewportCount = 1,
  225. .pViewports = &viewport,
  226. .scissorCount = 1,
  227. .pScissors = &scissor};
  228. VkPipelineRasterizationStateCreateInfo rasterizationState = {
  229. .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
  230. .depthClampEnable = false,
  231. .rasterizerDiscardEnable = false,
  232. .polygonMode = VK_POLYGON_MODE_FILL,
  233. .cullMode = VK_CULL_MODE_BACK_BIT,
  234. .frontFace = VK_FRONT_FACE_CLOCKWISE,
  235. .depthBiasEnable = false,
  236. .depthBiasConstantFactor = 0.0f,
  237. .depthBiasClamp = 0.0f,
  238. .depthBiasSlopeFactor = 0.0f,
  239. .lineWidth = 1.0f};
  240. VkPipelineMultisampleStateCreateInfo multisampleState = {
  241. .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
  242. .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
  243. .sampleShadingEnable = false,
  244. .minSampleShading = 1.0f,
  245. .pSampleMask = nullptr,
  246. .alphaToCoverageEnable = false,
  247. .alphaToOneEnable = false};
  248. VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {
  249. .blendEnable = false,
  250. .srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
  251. .dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
  252. .colorBlendOp = VK_BLEND_OP_ADD,
  253. .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
  254. .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
  255. .alphaBlendOp = VK_BLEND_OP_ADD,
  256. .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
  257. VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT};
  258. VkPipelineColorBlendStateCreateInfo colorBlendState = {
  259. .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
  260. .logicOpEnable = false,
  261. .logicOp = VK_LOGIC_OP_COPY,
  262. .attachmentCount = 1,
  263. .pAttachments = &colorBlendAttachmentState,
  264. .blendConstants = {0.0f, 0.0f, 0.0f, 0.0f}};
  265. Core::Array<VkDynamicState, 2> dynamicStates = {
  266. {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR}};
  267. VkPipelineDynamicStateCreateInfo dynamicState = {
  268. .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
  269. .dynamicStateCount = dynamicStates.getLength(),
  270. .pDynamicStates = dynamicStates.begin()};
  271. VkGraphicsPipelineCreateInfo info = {
  272. .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
  273. .stageCount = 2,
  274. .pStages = stages,
  275. .pVertexInputState = &vertexInputState,
  276. .pInputAssemblyState = &inputAssemblyState,
  277. .pTessellationState = nullptr,
  278. .pViewportState = &viewportState,
  279. .pRasterizationState = &rasterizationState,
  280. .pMultisampleState = &multisampleState,
  281. .pDepthStencilState = nullptr,
  282. .pColorBlendState = &colorBlendState,
  283. .pDynamicState = &dynamicState,
  284. .layout = pl,
  285. .renderPass = rp,
  286. .subpass = 0,
  287. .basePipelineHandle = VK_NULL_HANDLE,
  288. .basePipelineIndex = -1};
  289. VK_CHECK_TRUE(vkCreateGraphicsPipelines(
  290. pl.device, VK_NULL_HANDLE, 1, &info, nullptr, &handle));
  291. device = pl.device;
  292. return false;
  293. }
  294. bool CommandPool::init(VkDevice d, u32 queueFamily) {
  295. VkCommandPoolCreateInfo info = {
  296. .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
  297. .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
  298. .queueFamilyIndex = queueFamily};
  299. VK_CHECK_TRUE(vkCreateCommandPool(d, &info, nullptr, &handle));
  300. device = d;
  301. return false;
  302. }
  303. bool CommandBuffer::init(CommandPool& cp) {
  304. VkCommandBufferAllocateInfo info = {
  305. .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
  306. .commandPool = cp,
  307. .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
  308. .commandBufferCount = 1};
  309. VK_CHECK_TRUE(vkAllocateCommandBuffers(cp.device, &info, &handle));
  310. device = cp.device;
  311. return false;
  312. }
  313. void CommandBuffer::reset() {
  314. VK_CHECK_VOID(vkResetCommandBuffer(handle, 0));
  315. }
  316. void CommandBuffer::begin() {
  317. VkCommandBufferBeginInfo info = {
  318. .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
  319. VK_CHECK_VOID(vkBeginCommandBuffer(handle, &info));
  320. }
  321. void CommandBuffer::end() {
  322. VK_CHECK_VOID(vkEndCommandBuffer(handle));
  323. }
  324. void CommandBuffer::beginRenderPass(
  325. RenderPass& rp, Framebuffer& f, const VkExtent2D& size) {
  326. VkClearValue v = {.color = {.float32 = {0.0f, 0.0f, 0.0f, 1.0f}}};
  327. VkRenderPassBeginInfo info = {
  328. .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
  329. .renderPass = rp,
  330. .framebuffer = f,
  331. .renderArea = {.offset = {0, 0}, .extent = size},
  332. .clearValueCount = 1,
  333. .pClearValues = &v};
  334. vkCmdBeginRenderPass(handle, &info, VK_SUBPASS_CONTENTS_INLINE);
  335. }
  336. void CommandBuffer::endRenderPass() {
  337. vkCmdEndRenderPass(handle);
  338. }
  339. void CommandBuffer::bindPipeline(Pipeline& p) {
  340. vkCmdBindPipeline(handle, VK_PIPELINE_BIND_POINT_GRAPHICS, p);
  341. vkCmdSetViewport(handle, 0, 1, &p.viewport);
  342. vkCmdSetScissor(handle, 0, 1, &p.scissor);
  343. }
  344. void CommandBuffer::draw(u32 vertices) {
  345. vkCmdDraw(handle, vertices, 1, 0, 0);
  346. }
  347. bool Queue::init(VkDevice d, u32 queueFamily) {
  348. vkGetDeviceQueue(d, queueFamily, 0, &handle);
  349. return handle == VK_NULL_HANDLE;
  350. }
  351. void Queue::submit(
  352. CommandBuffer& cb, Fence& f, Semaphore& wait, Semaphore& signal,
  353. VkPipelineStageFlags flags) {
  354. VkSubmitInfo info = {
  355. .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
  356. .waitSemaphoreCount = 1,
  357. .pWaitSemaphores = wait,
  358. .pWaitDstStageMask = &flags,
  359. .commandBufferCount = 1,
  360. .pCommandBuffers = cb,
  361. .signalSemaphoreCount = 1,
  362. .pSignalSemaphores = signal};
  363. VK_CHECK_VOID(vkQueueSubmit(handle, 1, &info, f));
  364. }
  365. void Queue::present(Semaphore& signal, Swapchain& s, u32 index) {
  366. VkPresentInfoKHR info = {
  367. .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
  368. .waitSemaphoreCount = 1,
  369. .pWaitSemaphores = signal,
  370. .swapchainCount = 1,
  371. .pSwapchains = s,
  372. .pImageIndices = &index};
  373. VK_CHECK_VOID(vkQueuePresentKHR(handle, &info));
  374. }
  375. struct VulkanDummy {
  376. Core::Vulkan::Base base{};
  377. struct BaseData {
  378. u32 graphicsFamily = 0;
  379. u32 presentFamily = 0;
  380. VkSurfaceFormatKHR surfaceFormat{};
  381. VkPresentModeKHR presentMode{};
  382. };
  383. BaseData baseData{};
  384. Queue graphicsQueue{};
  385. Queue presentQueue{};
  386. VkExtent2D swapchainSize{};
  387. Swapchain swapchain{};
  388. SwapchainImages images{};
  389. PipelineLayout pipelineLayout{};
  390. RenderPass renderPass{};
  391. Pipeline pipeline{};
  392. Core::List<Vulkan::Framebuffer> framebuffers{};
  393. CommandPool commandPool{};
  394. size_t currentFrame = 0;
  395. bool shouldWait = false;
  396. struct Frame {
  397. CommandBuffer commandBuffer{};
  398. Semaphore imageAvailableSemaphore{};
  399. Semaphore renderFinishedSemaphore{};
  400. Fence inFlightFence{};
  401. };
  402. Core::Array<Frame, 2> frames{};
  403. static int getSurfaceFormatPoints(const VkSurfaceFormatKHR& sf) {
  404. if(sf.format == VK_FORMAT_B8G8R8A8_UNORM &&
  405. sf.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
  406. return 10;
  407. }
  408. return 1;
  409. }
  410. static int getSurfacePresentModePoints(VkPresentModeKHR m) {
  411. if(m == VK_PRESENT_MODE_MAILBOX_KHR) {
  412. return 5;
  413. } else if(m == VK_PRESENT_MODE_FIFO_KHR) {
  414. return 2;
  415. }
  416. return 0;
  417. }
  418. bool getSwapchainSize(VkExtent2D* size) {
  419. VkSurfaceCapabilitiesKHR c = {0};
  420. if(base.getSurfaceCapabilities(c)) {
  421. return true;
  422. }
  423. if(c.currentExtent.width != 0xFFFF'FFFFu &&
  424. c.currentExtent.height != 0xFFFF'FFFFu) {
  425. *size = c.currentExtent;
  426. LOG_INFO("Swapchain size: #x#", size->width, size->height);
  427. return false;
  428. }
  429. int w = 0;
  430. int h = 0;
  431. glfwGetFramebufferSize(Core::Window::get(), &w, &h);
  432. if(w <= 0 || h <= 0) {
  433. LOG_ERROR("Could not get framebuffer size");
  434. return true;
  435. }
  436. LOG_INFO("Framebuffer size: #x#", w, h);
  437. size->width = Core::clamp(
  438. static_cast<u32>(w), c.minImageExtent.width,
  439. c.maxImageExtent.width);
  440. size->height = Core::clamp(
  441. static_cast<u32>(h), c.minImageExtent.height,
  442. c.maxImageExtent.height);
  443. LOG_INFO("Swapchain size: #x#", size->width, size->height);
  444. return false;
  445. }
  446. bool initSwapchain() {
  447. Vulkan::Swapchain::Data d = {
  448. .base = base,
  449. .surfaceFormat = baseData.surfaceFormat,
  450. .presentMode = baseData.presentMode};
  451. if(getSwapchainSize(&d.size)) {
  452. LOG_ERROR("Could not retrieve any swapchain size");
  453. return true;
  454. }
  455. swapchainSize = d.size;
  456. d.queueFamilies.add(baseData.graphicsFamily);
  457. if(baseData.graphicsFamily != baseData.presentFamily) {
  458. d.queueFamilies.add(baseData.presentFamily);
  459. d.sharingMode = VK_SHARING_MODE_CONCURRENT;
  460. } else {
  461. d.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  462. }
  463. return swapchain.init(d);
  464. }
  465. bool initDevice() {
  466. bool same = baseData.graphicsFamily == baseData.presentFamily;
  467. Core::List<Vulkan::DeviceQueueData> data;
  468. data.add(baseData.graphicsFamily, 1.0f);
  469. if(!same) {
  470. data.add(baseData.presentFamily, 1.0f);
  471. };
  472. Core::List<const char*> extensions;
  473. extensions.add(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
  474. if(base.initDevice(data, extensions)) {
  475. return true;
  476. } else if(graphicsQueue.init(base, baseData.graphicsFamily)) {
  477. LOG_ERROR("Cannot get device graphics queue");
  478. return true;
  479. } else if(presentQueue.init(base, baseData.presentFamily)) {
  480. LOG_ERROR("Cannot get device present queue");
  481. return true;
  482. }
  483. return false;
  484. }
  485. static int getDevicePoints(Vulkan::Base& b, BaseData& d) {
  486. int points = 0;
  487. VkPhysicalDeviceProperties p;
  488. b.getPhysicalDeviceProperties(p);
  489. LOG_INFO("Checking '#'", p.deviceName);
  490. switch(p.deviceType) {
  491. case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: points += 100; break;
  492. case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: points += 50; break;
  493. case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: points += 20; break;
  494. default: break;
  495. }
  496. d.graphicsFamily = b.findQueueFamily(VK_QUEUE_GRAPHICS_BIT);
  497. if(d.graphicsFamily == Vulkan::INVALID_QUEUE_FAMILY) {
  498. LOG_INFO("> ... has no graphics family");
  499. points = -1;
  500. }
  501. d.presentFamily = b.findSurfaceQueueFamily();
  502. if(d.presentFamily == Vulkan::INVALID_QUEUE_FAMILY) {
  503. LOG_INFO("> ... has no present family");
  504. points = -1;
  505. }
  506. if(!b.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
  507. LOG_INFO("> ... has no swapchain support");
  508. points = -1;
  509. }
  510. if(b.findSurfaceFormat(d.surfaceFormat, getSurfaceFormatPoints)) {
  511. LOG_INFO("> ... has no matching surface format");
  512. points = -1;
  513. } else {
  514. points += getSurfaceFormatPoints(d.surfaceFormat);
  515. }
  516. if(b.findSurfacePresentMode(
  517. d.presentMode, getSurfacePresentModePoints)) {
  518. LOG_INFO("> ... has no matching present mode");
  519. points = -1;
  520. } else {
  521. points += getSurfacePresentModePoints(d.presentMode);
  522. }
  523. LOG_INFO("> Final points: #", points);
  524. return points;
  525. }
  526. bool initPhysicalDevice() {
  527. LOG_INFO("Searching for physical devices ...");
  528. if(base.findPhysicalDevice(baseData, getDevicePoints)) {
  529. LOG_ERROR("No matching physical device was found");
  530. return true;
  531. }
  532. VkPhysicalDeviceProperties p;
  533. base.getPhysicalDeviceProperties(p);
  534. LOG_INFO("Best Device: #", p.deviceName);
  535. return false;
  536. }
  537. bool initSwapchainImages() {
  538. if(images.init(swapchain, baseData.surfaceFormat.format)) {
  539. LOG_ERROR("Could not get swapchain images");
  540. return true;
  541. }
  542. LOG_INFO("Found # images", images.images.getLength());
  543. return false;
  544. }
  545. bool initPipeline() {
  546. pipeline.updateSize(swapchainSize.width, swapchainSize.height);
  547. return pipeline.init(pipelineLayout, renderPass);
  548. }
  549. bool initFramebuffers() {
  550. framebuffers.resize(images.imageViews.getLength());
  551. size_t i = 0;
  552. for(Framebuffer& f : framebuffers) {
  553. if(f.init(
  554. images.imageViews[i++], renderPass, swapchainSize.width,
  555. swapchainSize.height)) {
  556. return true;
  557. }
  558. }
  559. return false;
  560. }
  561. void fillCommandBuffer(CommandBuffer& cb, u32 index) {
  562. cb.begin();
  563. cb.beginRenderPass(renderPass, framebuffers[index], swapchainSize);
  564. cb.bindPipeline(pipeline);
  565. cb.draw(6);
  566. cb.endRenderPass();
  567. cb.end();
  568. }
  569. bool initFrames() {
  570. for(Frame& f : frames) {
  571. if(f.commandBuffer.init(commandPool) ||
  572. f.imageAvailableSemaphore.init(base) ||
  573. f.renderFinishedSemaphore.init(base) ||
  574. f.inFlightFence.init(base)) {
  575. return true;
  576. }
  577. }
  578. return false;
  579. }
  580. bool init() {
  581. return base.init() || initPhysicalDevice() || initDevice() ||
  582. initSwapchain() || initSwapchainImages() ||
  583. pipelineLayout.init(base) ||
  584. renderPass.init(base, baseData.surfaceFormat.format) ||
  585. initPipeline() || initFramebuffers() ||
  586. commandPool.init(base, baseData.graphicsFamily) || initFrames();
  587. }
  588. bool render() {
  589. if(shouldWait) {
  590. return false;
  591. }
  592. Frame& f = frames[currentFrame];
  593. f.inFlightFence.waitFor();
  594. f.inFlightFence.reset();
  595. u32 imageIndex = 0;
  596. if(swapchain.nextImage(imageIndex, f.imageAvailableSemaphore)) {
  597. return true;
  598. }
  599. f.commandBuffer.reset();
  600. fillCommandBuffer(f.commandBuffer, imageIndex);
  601. graphicsQueue.submit(
  602. f.commandBuffer, f.inFlightFence, f.imageAvailableSemaphore,
  603. f.renderFinishedSemaphore,
  604. VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
  605. presentQueue.present(f.renderFinishedSemaphore, swapchain, imageIndex);
  606. currentFrame = (currentFrame + 1) % frames.getLength();
  607. return false;
  608. }
  609. };
  610. static Core::UniquePointer<VulkanDummy> dummy;
  611. bool Vulkan::init() {
  612. dummy = new VulkanDummy();
  613. return dummy->init();
  614. }
  615. void Vulkan::render() {
  616. if(dummy->render()) {
  617. dummy->shouldWait = true;
  618. }
  619. }
  620. void Vulkan::destroy() {
  621. dummy->base.waitForIdle();
  622. dummy = nullptr;
  623. }