Graphics.cpp 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581
  1. #include "Graphics.h"
  2. #include "Buffer.h"
  3. #include "SDL_vulkan.h"
  4. #include "window/Window.h"
  5. #include "common/Exception.h"
  6. #include "Shader.h"
  7. #include "graphics/Texture.h"
  8. #include "Vulkan.h"
  9. #include "common/version.h"
  10. #include "common/pixelformat.h"
  11. #include <algorithm>
  12. #include <vector>
  13. #include <cstring>
  14. #include <set>
  15. #include <fstream>
  16. #include <iostream>
  17. #include <array>
  18. namespace love {
  19. namespace graphics {
  20. namespace vulkan {
  21. static VkIndexType getVulkanIndexBufferType(IndexDataType type) {
  22. switch (type) {
  23. case INDEX_UINT16: return VK_INDEX_TYPE_UINT16;
  24. case INDEX_UINT32: return VK_INDEX_TYPE_UINT32;
  25. default:
  26. throw love::Exception("unknown Index Data type");
  27. }
  28. }
  29. const std::vector<const char*> validationLayers = {
  30. "VK_LAYER_KHRONOS_validation"
  31. };
  32. const std::vector<const char*> deviceExtensions = {
  33. VK_KHR_SWAPCHAIN_EXTENSION_NAME,
  34. // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_push_descriptor.html
  35. VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME
  36. };
  37. #ifdef NDEBUG
  38. constexpr bool enableValidationLayers = false;
  39. #else
  40. constexpr bool enableValidationLayers = true;
  41. #endif
  42. constexpr int MAX_FRAMES_IN_FLIGHT = 2;
  43. constexpr uint32_t vulkanApiVersion = VK_API_VERSION_1_3;
  44. const char* Graphics::getName() const {
  45. return "love.graphics.vulkan";
  46. }
  47. const VkDevice Graphics::getDevice() const {
  48. return device;
  49. }
  50. const VkPhysicalDevice Graphics::getPhysicalDevice() const {
  51. return physicalDevice;
  52. }
  53. const VmaAllocator Graphics::getVmaAllocator() const {
  54. return vmaAllocator;
  55. }
  56. Graphics::~Graphics() {
  57. // We already cleaned those up by clearing out batchedDrawBuffers.
  58. // We set them to nullptr here so the base class doesn't crash
  59. // when it tries to free this.
  60. batchedDrawState.vb[0] = nullptr;
  61. batchedDrawState.vb[1] = nullptr;
  62. batchedDrawState.indexBuffer = nullptr;
  63. }
  64. // START OVERRIDEN FUNCTIONS
  65. love::graphics::Texture* Graphics::newTexture(const love::graphics::Texture::Settings& settings, const love::graphics::Texture::Slices* data) {
  66. return new Texture(this, settings, data);
  67. }
  68. love::graphics::Buffer* Graphics::newBuffer(const love::graphics::Buffer::Settings& settings, const std::vector<love::graphics::Buffer::DataDeclaration>& format, const void* data, size_t size, size_t arraylength) {
  69. return new Buffer(this, settings, format, data, size, arraylength);
  70. }
  71. // FIXME: clear stencil and depth missing.
  72. void Graphics::clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) {
  73. VkClearAttachment attachment{};
  74. if (color.hasValue) {
  75. attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  76. attachment.clearValue.color.float32[0] = static_cast<float>(color.value.r);
  77. attachment.clearValue.color.float32[1] = static_cast<float>(color.value.g);
  78. attachment.clearValue.color.float32[2] = static_cast<float>(color.value.b);
  79. attachment.clearValue.color.float32[3] = static_cast<float>(color.value.a);
  80. }
  81. VkClearRect rect{};
  82. rect.layerCount = 1;
  83. rect.rect.extent.width = static_cast<uint32_t>(currentViewportWidth);
  84. rect.rect.extent.height = static_cast<uint32_t>(currentViewportHeight);
  85. vkCmdClearAttachments(commandBuffers[imageIndex], 1, &attachment, 1, &rect);
  86. }
  87. void Graphics::clear(const std::vector<OptionalColorD>& colors, OptionalInt stencil, OptionalDouble depth) {
  88. std::vector<VkClearAttachment> attachments;
  89. for (const auto& color : colors) {
  90. VkClearAttachment attachment{};
  91. if (color.hasValue) {
  92. attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  93. attachment.clearValue.color.float32[0] = static_cast<float>(color.value.r);
  94. attachment.clearValue.color.float32[1] = static_cast<float>(color.value.g);
  95. attachment.clearValue.color.float32[2] = static_cast<float>(color.value.b);
  96. attachment.clearValue.color.float32[3] = static_cast<float>(color.value.a);
  97. }
  98. attachments.push_back(attachment);
  99. }
  100. VkClearRect rect{};
  101. rect.layerCount = 1;
  102. rect.rect.extent.width = static_cast<uint32_t>(currentViewportWidth);
  103. rect.rect.extent.height = static_cast<uint32_t>(currentViewportHeight);
  104. vkCmdClearAttachments(commandBuffers[imageIndex], static_cast<uint32_t>(attachments.size()), attachments.data(), 1, &rect);
  105. }
  106. void Graphics::present(void* screenshotCallbackdata) {
  107. if (!isActive()) {
  108. return;
  109. }
  110. flushBatchedDraws();
  111. endRecordingGraphicsCommands();
  112. if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) {
  113. vkWaitForFences(device, 1, &imagesInFlight.at(imageIndex), VK_TRUE, UINT64_MAX);
  114. }
  115. imagesInFlight[imageIndex] = inFlightFences[currentFrame];
  116. // all data transfers should happen before any draw calls.
  117. std::vector<VkCommandBuffer> submitCommandbuffers = { dataTransferCommandBuffers.at(currentFrame), commandBuffers.at(imageIndex) };
  118. VkSubmitInfo submitInfo{};
  119. submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
  120. VkSemaphore waitSemaphores[] = { imageAvailableSemaphores.at(currentFrame) };
  121. VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
  122. submitInfo.waitSemaphoreCount = 1;
  123. submitInfo.pWaitSemaphores = waitSemaphores;
  124. submitInfo.pWaitDstStageMask = waitStages;
  125. submitInfo.commandBufferCount = static_cast<uint32_t>(submitCommandbuffers.size());
  126. submitInfo.pCommandBuffers = submitCommandbuffers.data();
  127. VkSemaphore signalSemaphores[] = { renderFinishedSemaphores.at(currentFrame) };
  128. submitInfo.signalSemaphoreCount = 1;
  129. submitInfo.pSignalSemaphores = signalSemaphores;
  130. vkResetFences(device, 1, &inFlightFences[currentFrame]);
  131. if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences.at(currentFrame)) != VK_SUCCESS) {
  132. throw love::Exception("failed to submit draw command buffer");
  133. }
  134. VkPresentInfoKHR presentInfo{};
  135. presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
  136. presentInfo.waitSemaphoreCount = 1;
  137. presentInfo.pWaitSemaphores = signalSemaphores;
  138. VkSwapchainKHR swapChains[] = { swapChain };
  139. presentInfo.swapchainCount = 1;
  140. presentInfo.pSwapchains = swapChains;
  141. presentInfo.pImageIndices = &imageIndex;
  142. VkResult result = vkQueuePresentKHR(presentQueue, &presentInfo);
  143. if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
  144. framebufferResized = false;
  145. recreateSwapChain();
  146. }
  147. else if (result != VK_SUCCESS) {
  148. throw love::Exception("failed to present swap chain image");
  149. }
  150. currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
  151. updatedBatchedDrawBuffers();
  152. startRecordingGraphicsCommands();
  153. }
  154. void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight) {
  155. this->width = width;
  156. this->height = height;
  157. this->pixelWidth = pixelwidth;
  158. this->pixelHeight = pixelheight;
  159. resetProjection();
  160. }
  161. bool Graphics::setMode(void* context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) {
  162. cleanUpFunctions.clear();
  163. cleanUpFunctions.resize(MAX_FRAMES_IN_FLIGHT);
  164. createVulkanInstance();
  165. createSurface();
  166. pickPhysicalDevice();
  167. createLogicalDevice();
  168. initVMA();
  169. initCapabilities();
  170. createSwapChain();
  171. createImageViews();
  172. createSyncObjects();
  173. createCommandPool();
  174. createCommandBuffers();
  175. startRecordingGraphicsCommands();
  176. createQuadIndexBuffer();
  177. createDefaultTexture();
  178. createDefaultShaders();
  179. currentFrame = 0;
  180. created = true;
  181. float whiteColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
  182. batchedDrawBuffers.clear();
  183. batchedDrawBuffers.reserve(MAX_FRAMES_IN_FLIGHT);
  184. for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
  185. batchedDrawBuffers.emplace_back();
  186. // Initial sizes that should be good enough for most cases. It will
  187. // resize to fit if needed, later.
  188. batchedDrawBuffers[i].vertexBuffer1 = new StreamBuffer(this, BUFFERUSAGE_VERTEX, 1024 * 1024 * 1);
  189. batchedDrawBuffers[i].vertexBuffer2 = new StreamBuffer(this, BUFFERUSAGE_VERTEX, 256 * 1024 * 1);
  190. batchedDrawBuffers[i].indexBuffer = new StreamBuffer(this, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
  191. // sometimes the VertexColor is not set, so we manually adjust it to white color
  192. batchedDrawBuffers[i].constantColorBuffer = new StreamBuffer(this, BUFFERUSAGE_VERTEX, sizeof(whiteColor));
  193. auto mapInfo = batchedDrawBuffers[i].constantColorBuffer->map(sizeof(whiteColor));
  194. memcpy(mapInfo.data, whiteColor, sizeof(whiteColor));
  195. batchedDrawBuffers[i].constantColorBuffer->unmap(sizeof(whiteColor));
  196. batchedDrawBuffers[i].constantColorBuffer->markUsed(sizeof(whiteColor));
  197. }
  198. updatedBatchedDrawBuffers();
  199. Shader::current = Shader::standardShaders[graphics::Shader::StandardShader::STANDARD_DEFAULT];
  200. restoreState(states.back());
  201. setViewportSize(width, height, pixelwidth, pixelheight);
  202. renderTargetTexture = nullptr;
  203. currentViewportWidth = 0.0f;
  204. currentViewportHeight = 0.0f;
  205. Vulkan::resetShaderSwitches();
  206. return true;
  207. }
  208. void Graphics::initCapabilities() {
  209. // todo
  210. capabilities.features[FEATURE_MULTI_RENDER_TARGET_FORMATS] = false;
  211. capabilities.features[FEATURE_CLAMP_ZERO] = false;
  212. capabilities.features[FEATURE_CLAMP_ONE] = false;
  213. capabilities.features[FEATURE_BLEND_MINMAX] = false;
  214. capabilities.features[FEATURE_LIGHTEN] = false;
  215. capabilities.features[FEATURE_FULL_NPOT] = false;
  216. capabilities.features[FEATURE_PIXEL_SHADER_HIGHP] = true;
  217. capabilities.features[FEATURE_SHADER_DERIVATIVES] = false;
  218. capabilities.features[FEATURE_GLSL3] = true;
  219. capabilities.features[FEATURE_GLSL4] = true;
  220. capabilities.features[FEATURE_INSTANCING] = false;
  221. capabilities.features[FEATURE_TEXEL_BUFFER] = false;
  222. capabilities.features[FEATURE_INDEX_BUFFER_32BIT] = true;
  223. capabilities.features[FEATURE_COPY_BUFFER] = false;
  224. capabilities.features[FEATURE_COPY_BUFFER_TO_TEXTURE] = false;
  225. capabilities.features[FEATURE_COPY_TEXTURE_TO_BUFFER] = false;
  226. capabilities.features[FEATURE_COPY_RENDER_TARGET_TO_BUFFER] = false;
  227. static_assert(FEATURE_MAX_ENUM == 17, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
  228. VkPhysicalDeviceProperties properties;
  229. vkGetPhysicalDeviceProperties(physicalDevice, &properties);
  230. capabilities.limits[LIMIT_POINT_SIZE] = properties.limits.pointSizeRange[1];
  231. capabilities.limits[LIMIT_TEXTURE_SIZE] = properties.limits.maxImageDimension2D;
  232. capabilities.limits[LIMIT_TEXTURE_LAYERS] = properties.limits.maxImageArrayLayers;
  233. capabilities.limits[LIMIT_VOLUME_TEXTURE_SIZE] = properties.limits.maxImageDimension3D;
  234. capabilities.limits[LIMIT_CUBE_TEXTURE_SIZE] = properties.limits.maxImageDimensionCube;
  235. capabilities.limits[LIMIT_TEXEL_BUFFER_SIZE] = properties.limits.maxTexelBufferElements; // ?
  236. capabilities.limits[LIMIT_SHADER_STORAGE_BUFFER_SIZE] = properties.limits.maxStorageBufferRange; // ?
  237. capabilities.limits[LIMIT_THREADGROUPS_X] = 0; // todo
  238. capabilities.limits[LIMIT_THREADGROUPS_Y] = 0; // todo
  239. capabilities.limits[LIMIT_THREADGROUPS_Z] = 0; // todo
  240. capabilities.limits[LIMIT_RENDER_TARGETS] = 1; // todo
  241. capabilities.limits[LIMIT_TEXTURE_MSAA] = 1; // todo
  242. capabilities.limits[LIMIT_ANISOTROPY] = 1.0f; // todo
  243. static_assert(LIMIT_MAX_ENUM == 13, "Graphics::initCapabilities must be updated when adding a new system limit!");
  244. capabilities.textureTypes[TEXTURE_2D] = true;
  245. capabilities.textureTypes[TEXTURE_2D_ARRAY] = true;
  246. capabilities.textureTypes[TEXTURE_VOLUME] = false;
  247. capabilities.textureTypes[TEXTURE_CUBE] = false;
  248. }
  249. void Graphics::getAPIStats(int& shaderswitches) const {
  250. shaderswitches = Vulkan::getNumShaderSwitches();
  251. }
  252. void Graphics::unSetMode() {
  253. created = false;
  254. vkDeviceWaitIdle(device);
  255. Volatile::unloadAll();
  256. cleanup();
  257. }
  258. void Graphics::setActive(bool enable) {
  259. flushBatchedDraws();
  260. active = enable;
  261. }
  262. void Graphics::setFrontFaceWinding(Winding winding) {
  263. const auto& currentState = states.back();
  264. if (currentState.winding == winding) {
  265. return;
  266. }
  267. flushBatchedDraws();
  268. states.back().winding = winding;
  269. }
  270. void Graphics::setColorMask(ColorChannelMask mask) {
  271. flushBatchedDraws();
  272. states.back().colorMask = mask;
  273. }
  274. void Graphics::setBlendState(const BlendState& blend) {
  275. flushBatchedDraws();
  276. states.back().blend = blend;
  277. }
  278. void Graphics::setPointSize(float size) {
  279. if (size != states.back().pointSize)
  280. flushBatchedDraws();
  281. states.back().pointSize = size;
  282. }
  283. bool Graphics::usesGLSLES() const {
  284. return false;
  285. }
  286. Graphics::RendererInfo Graphics::getRendererInfo() const {
  287. VkPhysicalDeviceProperties deviceProperties;
  288. vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
  289. Graphics::RendererInfo info;
  290. info.device = deviceProperties.deviceName;
  291. info.vendor = Vulkan::getVendorName(deviceProperties.vendorID);
  292. info.version = Vulkan::getVulkanApiVersion(deviceProperties.apiVersion);
  293. info.name = "Vulkan";
  294. return info;
  295. }
  296. void Graphics::draw(const DrawCommand& cmd) {
  297. prepareDraw(*cmd.attributes, *cmd.buffers, cmd.texture, cmd.primitiveType, cmd.cullMode);
  298. vkCmdDraw(commandBuffers.at(imageIndex), static_cast<uint32_t>(cmd.vertexCount), static_cast<uint32_t>(cmd.instanceCount), static_cast<uint32_t>(cmd.vertexStart), 0);
  299. }
  300. void Graphics::draw(const DrawIndexedCommand& cmd) {
  301. prepareDraw(*cmd.attributes, *cmd.buffers, cmd.texture, cmd.primitiveType, cmd.cullMode);
  302. vkCmdBindIndexBuffer(commandBuffers.at(imageIndex), (VkBuffer)cmd.indexBuffer->getHandle(), static_cast<VkDeviceSize>(cmd.indexBufferOffset), getVulkanIndexBufferType(cmd.indexType));
  303. vkCmdDrawIndexed(commandBuffers.at(imageIndex), static_cast<uint32_t>(cmd.indexCount), static_cast<uint32_t>(cmd.instanceCount), 0, 0, 0);
  304. }
  305. void Graphics::drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture) {
  306. const int MAX_VERTICES_PER_DRAW = LOVE_UINT16_MAX;
  307. const int MAX_QUADS_PER_DRAW = MAX_VERTICES_PER_DRAW / 4;
  308. prepareDraw(attributes, buffers, texture, PRIMITIVE_TRIANGLES, CULL_BACK);
  309. vkCmdBindIndexBuffer(commandBuffers.at(imageIndex), (VkBuffer)quadIndexBuffer->getHandle(), 0, getVulkanIndexBufferType(INDEX_UINT16));
  310. int baseVertex = start * 4;
  311. for (int quadindex = 0; quadindex < count; quadindex += MAX_QUADS_PER_DRAW) {
  312. int quadcount = std::min(MAX_QUADS_PER_DRAW, count - quadindex);
  313. vkCmdDrawIndexed(commandBuffers.at(imageIndex), static_cast<uint32_t>(quadcount * 6), 1, 0, baseVertex, 0);
  314. baseVertex += quadcount * 4;
  315. }
  316. }
  317. void Graphics::setColor(Colorf c) {
  318. c.r = std::min(std::max(c.r, 0.0f), 1.0f);
  319. c.g = std::min(std::max(c.g, 0.0f), 1.0f);
  320. c.b = std::min(std::max(c.b, 0.0f), 1.0f);
  321. c.a = std::min(std::max(c.a, 0.0f), 1.0f);
  322. states.back().color = c;
  323. }
  324. void Graphics::setScissor(const Rect& rect) {
  325. flushBatchedDraws();
  326. states.back().scissor = true;
  327. states.back().scissorRect = rect;
  328. }
  329. void Graphics::setScissor() {
  330. flushBatchedDraws();
  331. states.back().scissor = false;
  332. }
  333. void Graphics::setWireframe(bool enable) {
  334. flushBatchedDraws();
  335. states.back().wireframe = enable;
  336. }
  337. PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const {
  338. switch (format) {
  339. case PIXELFORMAT_NORMAL:
  340. if (isGammaCorrect()) {
  341. return PIXELFORMAT_RGBA8_UNORM_sRGB;
  342. }
  343. else {
  344. return PIXELFORMAT_RGBA8_UNORM;
  345. }
  346. case PIXELFORMAT_HDR:
  347. return PIXELFORMAT_RGBA16_FLOAT;
  348. default:
  349. return format;
  350. }
  351. }
  352. bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) {
  353. return true;
  354. }
  355. Renderer Graphics::getRenderer() const {
  356. return RENDERER_VULKAN;
  357. }
  358. graphics::StreamBuffer* Graphics::newStreamBuffer(BufferUsage type, size_t size) {
  359. return new StreamBuffer(this, type, size);
  360. }
  361. Matrix4 Graphics::computeDeviceProjection(const Matrix4& projection, bool rendertotexture) const {
  362. uint32 flags = DEVICE_PROJECTION_DEFAULT;
  363. return calculateDeviceProjection(projection, flags);
  364. }
  365. void Graphics::setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) {
  366. endRenderPass();
  367. if (rts.colors.size() == 0) {
  368. startRenderPass(nullptr, swapChainExtent.width, swapChainExtent.height);
  369. } else {
  370. // fixme: multi canvas render.
  371. auto& firstRenderTarget = rts.getFirstTarget();
  372. startRenderPass(static_cast<Texture*>(firstRenderTarget.texture), pixelw, pixelh);
  373. }
  374. }
  375. // END IMPLEMENTATION OVERRIDDEN FUNCTIONS
  376. void Graphics::startRecordingGraphicsCommands() {
  377. vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
  378. while (true) {
  379. VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
  380. if (result == VK_ERROR_OUT_OF_DATE_KHR) {
  381. recreateSwapChain();
  382. continue;
  383. }
  384. else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
  385. throw love::Exception("failed to acquire swap chain image");
  386. }
  387. break;
  388. }
  389. for (auto& cleanUpFn : cleanUpFunctions.at(currentFrame)) {
  390. cleanUpFn();
  391. }
  392. cleanUpFunctions.at(currentFrame).clear();
  393. VkCommandBufferBeginInfo beginInfo{};
  394. beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  395. beginInfo.flags = 0;
  396. beginInfo.pInheritanceInfo = nullptr;
  397. if (vkBeginCommandBuffer(commandBuffers.at(imageIndex), &beginInfo) != VK_SUCCESS) {
  398. throw love::Exception("failed to begin recording command buffer");
  399. }
  400. if (vkBeginCommandBuffer(dataTransferCommandBuffers.at(currentFrame), &beginInfo) != VK_SUCCESS) {
  401. throw love::Exception("failed to begin recording data transfer command buffer");
  402. }
  403. Vulkan::cmdTransitionImageLayout(commandBuffers.at(imageIndex), swapChainImages[imageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
  404. startRenderPass(nullptr, swapChainExtent.width, swapChainExtent.height);
  405. Vulkan::resetShaderSwitches();
  406. }
  407. void Graphics::endRecordingGraphicsCommands() {
  408. endRenderPass();
  409. Vulkan::cmdTransitionImageLayout(commandBuffers.at(imageIndex), swapChainImages[imageIndex], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
  410. if (vkEndCommandBuffer(commandBuffers.at(imageIndex)) != VK_SUCCESS) {
  411. throw love::Exception("failed to record command buffer");
  412. }
  413. if (vkEndCommandBuffer(dataTransferCommandBuffers.at(currentFrame)) != VK_SUCCESS) {
  414. throw love::Exception("failed to record data transfer command buffer");
  415. }
  416. }
  417. void Graphics::updatedBatchedDrawBuffers() {
  418. batchedDrawState.vb[0] = batchedDrawBuffers[currentFrame].vertexBuffer1;
  419. batchedDrawState.vb[0]->nextFrame();
  420. batchedDrawState.vb[1] = batchedDrawBuffers[currentFrame].vertexBuffer2;
  421. batchedDrawState.vb[1]->nextFrame();
  422. batchedDrawState.indexBuffer = batchedDrawBuffers[currentFrame].indexBuffer;
  423. batchedDrawState.indexBuffer->nextFrame();
  424. }
  425. uint32_t Graphics::getNumImagesInFlight() const {
  426. return MAX_FRAMES_IN_FLIGHT;
  427. }
  428. const VkDeviceSize Graphics::getMinUniformBufferOffsetAlignment() const {
  429. return minUniformBufferOffsetAlignment;
  430. }
  431. graphics::Texture* Graphics::getDefaultTexture() const {
  432. return dynamic_cast<graphics::Texture*>(standardTexture.get());
  433. }
  434. const PFN_vkCmdPushDescriptorSetKHR Graphics::getVkCmdPushDescriptorSetKHRFunctionPointer() const {
  435. return vkCmdPushDescriptorSet;
  436. }
  437. VkCommandBuffer Graphics::getDataTransferCommandBuffer() {
  438. return dataTransferCommandBuffers.at(currentFrame);
  439. }
  440. void Graphics::queueCleanUp(std::function<void()> cleanUp) {
  441. cleanUpFunctions.at(currentFrame).push_back(std::move(cleanUp));
  442. }
  443. VkCommandBuffer Graphics::beginSingleTimeCommands() {
  444. VkCommandBufferAllocateInfo allocInfo{};
  445. allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
  446. allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
  447. allocInfo.commandPool = commandPool;
  448. allocInfo.commandBufferCount = 1;
  449. VkCommandBuffer commandBuffer;
  450. vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer);
  451. VkCommandBufferBeginInfo beginInfo{};
  452. beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  453. beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
  454. vkBeginCommandBuffer(commandBuffer, &beginInfo);
  455. return commandBuffer;
  456. }
  457. void Graphics::endSingleTimeCommands(VkCommandBuffer commandBuffer) {
  458. vkEndCommandBuffer(commandBuffer);
  459. VkSubmitInfo submitInfo{};
  460. submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
  461. submitInfo.commandBufferCount = 1;
  462. submitInfo.pCommandBuffers = &commandBuffer;
  463. vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
  464. vkQueueWaitIdle(graphicsQueue);
  465. vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
  466. }
  467. graphics::Shader::BuiltinUniformData Graphics::getCurrentBuiltinUniformData() {
  468. love::graphics::Shader::BuiltinUniformData data;
  469. data.transformMatrix = getTransform();
  470. data.projectionMatrix = getDeviceProjection();
  471. // The normal matrix is the transpose of the inverse of the rotation portion
  472. // (top-left 3x3) of the transform matrix.
  473. {
  474. Matrix3 normalmatrix = Matrix3(data.transformMatrix).transposedInverse();
  475. const float* e = normalmatrix.getElements();
  476. for (int i = 0; i < 3; i++)
  477. {
  478. data.normalMatrix[i].x = e[i * 3 + 0];
  479. data.normalMatrix[i].y = e[i * 3 + 1];
  480. data.normalMatrix[i].z = e[i * 3 + 2];
  481. data.normalMatrix[i].w = 0.0f;
  482. }
  483. }
  484. // Store DPI scale in an unused component of another vector.
  485. data.normalMatrix[0].w = (float)getCurrentDPIScale();
  486. // Same with point size.
  487. data.normalMatrix[1].w = getPointSize();
  488. data.screenSizeParams.x = static_cast<float>(swapChainExtent.width);
  489. data.screenSizeParams.y = static_cast<float>(swapChainExtent.height);
  490. data.screenSizeParams.z = 1.0f;
  491. data.screenSizeParams.w = 0.0f;
  492. data.constantColor = getColor();
  493. gammaCorrectColor(data.constantColor);
  494. return data;
  495. }
  496. void Graphics::createVulkanInstance() {
  497. if (enableValidationLayers && !checkValidationSupport()) {
  498. throw love::Exception("validation layers requested, but not available");
  499. }
  500. VkApplicationInfo appInfo{};
  501. appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
  502. appInfo.pApplicationName = "LOVE";
  503. appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); //todo, get this version from somewhere else?
  504. appInfo.pEngineName = "LOVE Engine";
  505. appInfo.engineVersion = VK_MAKE_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_REV);
  506. appInfo.apiVersion = vulkanApiVersion;
  507. VkInstanceCreateInfo createInfo{};
  508. createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
  509. createInfo.pApplicationInfo = &appInfo;
  510. createInfo.pNext = nullptr;
  511. auto window = Module::getInstance<love::window::Window>(M_WINDOW);
  512. const void* handle = window->getHandle();
  513. unsigned int count;
  514. if (SDL_Vulkan_GetInstanceExtensions((SDL_Window*)handle, &count, nullptr) != SDL_TRUE) {
  515. throw love::Exception("couldn't retrieve sdl vulkan extensions");
  516. }
  517. std::vector<const char*> extensions = {}; // can add more here
  518. size_t addition_extension_count = extensions.size();
  519. extensions.resize(addition_extension_count + count);
  520. if (SDL_Vulkan_GetInstanceExtensions((SDL_Window*)handle, &count, extensions.data() + addition_extension_count) != SDL_TRUE) {
  521. throw love::Exception("couldn't retrieve sdl vulkan extensions");
  522. }
  523. createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
  524. createInfo.ppEnabledExtensionNames = extensions.data();
  525. if (enableValidationLayers) {
  526. createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
  527. createInfo.ppEnabledLayerNames = validationLayers.data();
  528. }
  529. else {
  530. createInfo.enabledLayerCount = 0;
  531. createInfo.ppEnabledLayerNames = nullptr;
  532. }
  533. if (vkCreateInstance(
  534. &createInfo,
  535. nullptr,
  536. &instance) != VK_SUCCESS) {
  537. throw love::Exception("couldn't create vulkan instance");
  538. }
  539. }
  540. bool Graphics::checkValidationSupport() {
  541. uint32_t layerCount;
  542. vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
  543. std::vector<VkLayerProperties> availableLayers(layerCount);
  544. vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
  545. for (const char* layerName : validationLayers) {
  546. bool layerFound = false;
  547. for (const auto& layerProperties : availableLayers) {
  548. if (strcmp(layerName, layerProperties.layerName) == 0) {
  549. layerFound = true;
  550. break;
  551. }
  552. }
  553. if (!layerFound) {
  554. return false;
  555. }
  556. }
  557. return true;
  558. }
  559. void Graphics::pickPhysicalDevice() {
  560. uint32_t deviceCount = 0;
  561. vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
  562. if (deviceCount == 0) {
  563. throw love::Exception("failed to find GPUs with Vulkan support");
  564. }
  565. std::vector<VkPhysicalDevice> devices(deviceCount);
  566. vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
  567. std::multimap<int, VkPhysicalDevice> candidates;
  568. for (const auto& device : devices) {
  569. int score = rateDeviceSuitability(device);
  570. candidates.insert(std::make_pair(score, device));
  571. }
  572. if (candidates.rbegin()->first > 0) {
  573. physicalDevice = candidates.rbegin()->second;
  574. }
  575. else {
  576. throw love::Exception("failed to find a suitable gpu");
  577. }
  578. VkPhysicalDeviceProperties properties;
  579. vkGetPhysicalDeviceProperties(physicalDevice, &properties);
  580. minUniformBufferOffsetAlignment = properties.limits.minUniformBufferOffsetAlignment;
  581. }
  582. bool Graphics::checkDeviceExtensionSupport(VkPhysicalDevice device) {
  583. uint32_t extensionCount;
  584. vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
  585. std::vector<VkExtensionProperties> availableExtensions(extensionCount);
  586. vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
  587. std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
  588. for (const auto& extension : availableExtensions) {
  589. requiredExtensions.erase(extension.extensionName);
  590. }
  591. return requiredExtensions.empty();
  592. }
  593. // if the score is nonzero then the device is suitable.
  594. // A higher rating means generally better performance
  595. // if the score is 0 the device is unsuitable
  596. int Graphics::rateDeviceSuitability(VkPhysicalDevice device) {
  597. VkPhysicalDeviceProperties deviceProperties;
  598. VkPhysicalDeviceFeatures deviceFeatures;
  599. vkGetPhysicalDeviceProperties(device, &deviceProperties);
  600. vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
  601. int score = 1;
  602. // optional
  603. if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
  604. score += 1000;
  605. }
  606. if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) {
  607. score += 100;
  608. }
  609. if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU) {
  610. score += 10;
  611. }
  612. // definitely needed
  613. QueueFamilyIndices indices = findQueueFamilies(device);
  614. if (!indices.isComplete()) {
  615. score = 0;
  616. }
  617. bool extensionsSupported = checkDeviceExtensionSupport(device);
  618. if (!extensionsSupported) {
  619. score = 0;
  620. }
  621. if (extensionsSupported) {
  622. auto swapChainSupport = querySwapChainSupport(device);
  623. bool swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
  624. if (!swapChainAdequate) {
  625. score = 0;
  626. }
  627. }
  628. if (!deviceFeatures.samplerAnisotropy) {
  629. score = 0;
  630. }
  631. if (!deviceFeatures.fillModeNonSolid) {
  632. score = 0;
  633. }
  634. return score;
  635. }
  636. QueueFamilyIndices Graphics::findQueueFamilies(VkPhysicalDevice device) {
  637. QueueFamilyIndices indices;
  638. uint32_t queueFamilyCount = 0;
  639. vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
  640. std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
  641. vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
  642. int i = 0;
  643. for (const auto& queueFamily : queueFamilies) {
  644. if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
  645. indices.graphicsFamily = i;
  646. }
  647. VkBool32 presentSupport = false;
  648. vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
  649. if (presentSupport) {
  650. indices.presentFamily = i;
  651. }
  652. if (indices.isComplete()) {
  653. break;
  654. }
  655. i++;
  656. }
  657. return indices;
  658. }
  659. void Graphics::createLogicalDevice() {
  660. QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
  661. std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
  662. std::set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value(), indices.presentFamily.value() };
  663. float queuePriority = 1.0f;
  664. for (uint32_t queueFamily : uniqueQueueFamilies) {
  665. VkDeviceQueueCreateInfo queueCreateInfo{};
  666. queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
  667. queueCreateInfo.queueFamilyIndex = queueFamily;
  668. queueCreateInfo.queueCount = 1;
  669. queueCreateInfo.pQueuePriorities = &queuePriority;
  670. queueCreateInfos.push_back(queueCreateInfo);
  671. }
  672. VkPhysicalDeviceDynamicRenderingFeatures dynamicRenderingFeature{};
  673. dynamicRenderingFeature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES;
  674. dynamicRenderingFeature.dynamicRendering = VK_TRUE;
  675. VkPhysicalDeviceFeatures deviceFeatures{};
  676. deviceFeatures.samplerAnisotropy = VK_TRUE;
  677. deviceFeatures.fillModeNonSolid = VK_TRUE;
  678. VkDeviceCreateInfo createInfo{};
  679. createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
  680. createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
  681. createInfo.pQueueCreateInfos = queueCreateInfos.data();
  682. createInfo.pEnabledFeatures = &deviceFeatures;
  683. createInfo.pNext = &dynamicRenderingFeature;
  684. createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
  685. createInfo.ppEnabledExtensionNames = deviceExtensions.data();
  686. // can this be removed?
  687. if (enableValidationLayers) {
  688. createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
  689. createInfo.ppEnabledLayerNames = validationLayers.data();
  690. }
  691. else {
  692. createInfo.enabledLayerCount = 0;
  693. }
  694. if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
  695. throw love::Exception("failed to create logical device");
  696. }
  697. vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
  698. vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
  699. vkCmdPushDescriptorSet = (PFN_vkCmdPushDescriptorSetKHR) vkGetDeviceProcAddr(device, "vkCmdPushDescriptorSetKHR");
  700. if (!vkCmdPushDescriptorSet) {
  701. // fixme: how widely adopted is this extension?
  702. throw love::Exception("could not get a valid function pointer for vkCmdPushDescriptorSetKHR");
  703. }
  704. }
  705. void Graphics::initVMA() {
  706. VmaVulkanFunctions vulkanFunctions = {};
  707. vulkanFunctions.vkGetInstanceProcAddr = &vkGetInstanceProcAddr;
  708. vulkanFunctions.vkGetDeviceProcAddr = &vkGetDeviceProcAddr;
  709. VmaAllocatorCreateInfo allocatorCreateInfo = {};
  710. allocatorCreateInfo.vulkanApiVersion = vulkanApiVersion;
  711. allocatorCreateInfo.physicalDevice = physicalDevice;
  712. allocatorCreateInfo.device = device;
  713. allocatorCreateInfo.instance = instance;
  714. allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions;
  715. if (vmaCreateAllocator(&allocatorCreateInfo, &vmaAllocator) != VK_SUCCESS) {
  716. throw love::Exception("failed to create vma allocator");
  717. }
  718. }
  719. void Graphics::createSurface() {
  720. auto window = Module::getInstance<love::window::Window>(M_WINDOW);
  721. const void* handle = window->getHandle();
  722. if (SDL_Vulkan_CreateSurface((SDL_Window*)handle, instance, &surface) != SDL_TRUE) {
  723. throw love::Exception("failed to create window surface");
  724. }
  725. }
  726. SwapChainSupportDetails Graphics::querySwapChainSupport(VkPhysicalDevice device) {
  727. SwapChainSupportDetails details;
  728. vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
  729. uint32_t formatCount;
  730. vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
  731. if (formatCount != 0) {
  732. details.formats.resize(formatCount);
  733. vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
  734. }
  735. uint32_t presentModeCount;
  736. vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
  737. if (presentModeCount != 0) {
  738. details.presentModes.resize(presentModeCount);
  739. vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
  740. }
  741. return details;
  742. }
  743. void Graphics::createSwapChain() {
  744. SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);
  745. VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
  746. VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
  747. VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);
  748. uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
  749. if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {
  750. imageCount = swapChainSupport.capabilities.maxImageCount;
  751. }
  752. VkSwapchainCreateInfoKHR createInfo{};
  753. createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
  754. createInfo.surface = surface;
  755. createInfo.minImageCount = imageCount;
  756. createInfo.imageFormat = surfaceFormat.format;
  757. createInfo.imageColorSpace = surfaceFormat.colorSpace;
  758. createInfo.imageExtent = extent;
  759. createInfo.imageArrayLayers = 1;
  760. createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
  761. QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
  762. uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(), indices.presentFamily.value() };
  763. if (indices.graphicsFamily != indices.presentFamily) {
  764. createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
  765. createInfo.queueFamilyIndexCount = 2;
  766. createInfo.pQueueFamilyIndices = queueFamilyIndices;
  767. }
  768. else {
  769. createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
  770. createInfo.queueFamilyIndexCount = 0;
  771. createInfo.pQueueFamilyIndices = nullptr;
  772. }
  773. createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
  774. createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
  775. createInfo.presentMode = presentMode;
  776. createInfo.clipped = VK_TRUE;
  777. createInfo.oldSwapchain = VK_NULL_HANDLE;
  778. if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
  779. throw love::Exception("failed to create swap chain");
  780. }
  781. vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
  782. swapChainImages.resize(imageCount);
  783. vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
  784. swapChainImageFormat = surfaceFormat.format;
  785. swapChainExtent = extent;
  786. }
  787. VkSurfaceFormatKHR Graphics::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) {
  788. for (const auto& availableFormat : availableFormats) {
  789. // fixme: what if this format and colorspace is not available?
  790. if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
  791. return availableFormat;
  792. }
  793. }
  794. return availableFormats[0];
  795. }
  796. VkPresentModeKHR Graphics::chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) {
  797. // needed ?
  798. for (const auto& availablePresentMode : availablePresentModes) {
  799. if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
  800. return availablePresentMode;
  801. }
  802. }
  803. return VK_PRESENT_MODE_FIFO_KHR;
  804. }
  805. VkExtent2D Graphics::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {
  806. if (capabilities.currentExtent.width != UINT32_MAX) {
  807. return capabilities.currentExtent;
  808. }
  809. else {
  810. auto window = Module::getInstance<love::window::Window>(M_WINDOW);
  811. const void* handle = window->getHandle();
  812. int width, height;
  813. // is this the equivalent of glfwGetFramebufferSize ?
  814. SDL_Vulkan_GetDrawableSize((SDL_Window*)handle, &width, &height);
  815. VkExtent2D actualExtent = {
  816. static_cast<uint32_t>(width),
  817. static_cast<uint32_t>(height)
  818. };
  819. actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
  820. actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
  821. return actualExtent;
  822. }
  823. }
  824. void Graphics::createImageViews() {
  825. swapChainImageViews.resize(swapChainImages.size());
  826. for (size_t i = 0; i < swapChainImages.size(); i++) {
  827. VkImageViewCreateInfo createInfo{};
  828. createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
  829. createInfo.image = swapChainImages.at(i);
  830. createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
  831. createInfo.format = swapChainImageFormat;
  832. createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
  833. createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
  834. createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
  835. createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
  836. createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  837. createInfo.subresourceRange.baseMipLevel = 0;
  838. createInfo.subresourceRange.levelCount = 1;
  839. createInfo.subresourceRange.baseArrayLayer = 0;
  840. createInfo.subresourceRange.layerCount = 1;
  841. if (vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews.at(i)) != VK_SUCCESS) {
  842. throw love::Exception("failed to create image views");
  843. }
  844. }
  845. }
  846. void Graphics::createDefaultShaders() {
  847. for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++) {
  848. auto stype = (Shader::StandardShader)i;
  849. if (!Shader::standardShaders[i]) {
  850. std::vector<std::string> stages;
  851. stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_VERTEX));
  852. stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_PIXEL));
  853. Shader::standardShaders[i] = newShader(stages, {});
  854. }
  855. }
  856. }
  857. bool Graphics::usesConstantVertexColor(const VertexAttributes& vertexAttributes) {
  858. return !!(vertexAttributes.enableBits & (1u << ATTRIB_COLOR));
  859. }
  860. void Graphics::createVulkanVertexFormat(
  861. VertexAttributes vertexAttributes,
  862. std::vector<VkVertexInputBindingDescription> &bindingDescriptions,
  863. std::vector<VkVertexInputAttributeDescription> &attributeDescriptions) {
  864. std::set<uint32_t> usedBuffers;
  865. auto allBits = vertexAttributes.enableBits;
  866. bool usesColor = false;
  867. uint8_t highestBufferBinding = 0;
  868. for (uint32_t i = 0; i < VertexAttributes::MAX; i++) { // change to loop like in opengl implementation ?
  869. uint32 bit = 1u << i;
  870. if (allBits & bit) {
  871. if (i == ATTRIB_COLOR) {
  872. usesColor = true;
  873. }
  874. auto attrib = vertexAttributes.attribs[i];
  875. auto bufferBinding = attrib.bufferIndex;
  876. if (usedBuffers.find(bufferBinding) == usedBuffers.end()) { // use .contains() when c++20 is enabled
  877. usedBuffers.insert(bufferBinding);
  878. VkVertexInputBindingDescription bindingDescription{};
  879. bindingDescription.binding = bufferBinding;
  880. if (vertexAttributes.instanceBits & (1u << bufferBinding)) {
  881. bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
  882. }
  883. else {
  884. bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
  885. }
  886. bindingDescription.stride = vertexAttributes.bufferLayouts[bufferBinding].stride;
  887. bindingDescriptions.push_back(bindingDescription);
  888. highestBufferBinding = std::max(highestBufferBinding, bufferBinding);
  889. }
  890. VkVertexInputAttributeDescription attributeDescription{};
  891. attributeDescription.location = i;
  892. attributeDescription.binding = bufferBinding;
  893. attributeDescription.offset = attrib.offsetFromVertex;
  894. attributeDescription.format = Vulkan::getVulkanVertexFormat(attrib.format);
  895. attributeDescriptions.push_back(attributeDescription);
  896. }
  897. }
  898. // do we need to use a constant VertexColor?
  899. if (!usesColor) {
  900. // FIXME: is there a case where gaps happen between buffer bindings?
  901. // then this doesn't work. We might need to enable null buffers again.
  902. const auto constantColorBufferBinding = highestBufferBinding + 1;
  903. VkVertexInputBindingDescription bindingDescription{};
  904. bindingDescription.binding = constantColorBufferBinding;
  905. bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
  906. bindingDescription.stride = 0; // no stride, will always read the same color multiple times.
  907. bindingDescriptions.push_back(bindingDescription);
  908. VkVertexInputAttributeDescription attributeDescription{};
  909. attributeDescription.binding = constantColorBufferBinding;
  910. attributeDescription.location = ATTRIB_COLOR;
  911. attributeDescription.offset = 0;
  912. attributeDescription.format = VK_FORMAT_R32G32B32A32_SFLOAT;
  913. attributeDescriptions.push_back(attributeDescription);
  914. }
  915. }
  916. void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture, PrimitiveType primitiveType, CullMode cullmode) {
  917. GraphicsPipelineConfiguration configuration;
  918. configuration.vertexAttributes = attributes;
  919. configuration.shader = (Shader*)Shader::current;
  920. configuration.primitiveType = primitiveType;
  921. configuration.wireFrame = states.back().wireframe;
  922. configuration.blendState = states.back().blend;
  923. configuration.colorChannelMask = states.back().colorMask;
  924. configuration.winding = states.back().winding;
  925. configuration.cullmode = cullmode;
  926. configuration.framebufferFormat = currentFramebufferOutputFormat;
  927. configuration.viewportWidth = currentViewportWidth;
  928. configuration.viewportHeight = currentViewportHeight;
  929. if (states.back().scissor) {
  930. configuration.scissorRect = states.back().scissorRect;
  931. }
  932. else {
  933. configuration.scissorRect = std::nullopt;
  934. }
  935. std::vector<VkBuffer> bufferVector;
  936. std::vector<VkDeviceSize> offsets;
  937. for (uint32_t i = 0; i < VertexAttributes::MAX; i++) {
  938. if (buffers.useBits & (1u << i)) {
  939. bufferVector.push_back((VkBuffer)buffers.info[i].buffer->getHandle());
  940. offsets.push_back((VkDeviceSize)buffers.info[i].offset);
  941. }
  942. }
  943. if (usesConstantVertexColor(attributes)) {
  944. bufferVector.push_back((VkBuffer)batchedDrawBuffers[currentFrame].constantColorBuffer->getHandle());
  945. offsets.push_back((VkDeviceSize)0);
  946. }
  947. auto currentUniformData = getCurrentBuiltinUniformData();
  948. configuration.shader->setUniformData(currentUniformData);
  949. if (texture == nullptr) {
  950. configuration.shader->setMainTex(standardTexture.get());
  951. }
  952. else {
  953. configuration.shader->setMainTex(texture);
  954. }
  955. ensureGraphicsPipelineConfiguration(configuration);
  956. configuration.shader->cmdPushDescriptorSets(commandBuffers.at(imageIndex), static_cast<uint32_t>(currentFrame));
  957. vkCmdBindVertexBuffers(commandBuffers.at(imageIndex), 0, static_cast<uint32_t>(bufferVector.size()), bufferVector.data(), offsets.data());
  958. }
  959. void Graphics::startRenderPass(Texture* texture, uint32_t w, uint32_t h) {
  960. VkRenderingAttachmentInfo colorAttachmentInfo{};
  961. colorAttachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
  962. colorAttachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
  963. colorAttachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
  964. if (texture) {
  965. colorAttachmentInfo.imageView = (VkImageView)texture->getRenderTargetHandle();
  966. auto vulkanFormat = Vulkan::getTextureFormat(texture->getPixelFormat());
  967. currentFramebufferOutputFormat = vulkanFormat.internalFormat;
  968. renderTargetTexture = texture;
  969. } else {
  970. colorAttachmentInfo.imageView = swapChainImageViews[imageIndex];
  971. currentFramebufferOutputFormat = swapChainImageFormat;
  972. renderTargetTexture = nullptr;
  973. }
  974. colorAttachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
  975. VkRenderingInfo renderingInfo{};
  976. renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO;
  977. renderingInfo.renderArea.extent.width = w;
  978. renderingInfo.renderArea.extent.height = h;
  979. renderingInfo.layerCount = 1;
  980. renderingInfo.colorAttachmentCount = 1;
  981. renderingInfo.pColorAttachments = &colorAttachmentInfo;
  982. currentViewportWidth = (float)w;
  983. currentViewportHeight = (float)h;
  984. if (renderTargetTexture) {
  985. Vulkan::cmdTransitionImageLayout(commandBuffers.at(imageIndex), (VkImage)texture->getHandle(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
  986. }
  987. vkCmdBeginRendering(commandBuffers.at(imageIndex), &renderingInfo);
  988. currentGraphicsPipeline = VK_NULL_HANDLE;
  989. }
  990. void Graphics::endRenderPass() {
  991. vkCmdEndRendering(commandBuffers.at(imageIndex));
  992. if (renderTargetTexture) {
  993. Vulkan::cmdTransitionImageLayout(commandBuffers.at(imageIndex), (VkImage)renderTargetTexture->getHandle(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
  994. renderTargetTexture = nullptr;
  995. }
  996. }
  997. VkSampler Graphics::createSampler(const SamplerState& samplerState) {
  998. VkPhysicalDeviceProperties properties{};
  999. vkGetPhysicalDeviceProperties(physicalDevice, &properties);
  1000. VkSamplerCreateInfo samplerInfo{};
  1001. samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
  1002. samplerInfo.magFilter = Vulkan::getFilter(samplerState.magFilter);
  1003. samplerInfo.minFilter = Vulkan::getFilter(samplerState.minFilter);
  1004. samplerInfo.addressModeU = Vulkan::getWrapMode(samplerState.wrapU);
  1005. samplerInfo.addressModeV = Vulkan::getWrapMode(samplerState.wrapV);
  1006. samplerInfo.addressModeW = Vulkan::getWrapMode(samplerState.wrapW);
  1007. samplerInfo.anisotropyEnable = VK_TRUE;
  1008. samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy; // fixme: samplerState.maxAnisotropy
  1009. samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
  1010. samplerInfo.unnormalizedCoordinates = VK_FALSE;
  1011. if (samplerState.depthSampleMode.hasValue) {
  1012. samplerInfo.compareEnable = VK_TRUE;
  1013. samplerInfo.compareOp = Vulkan::getCompareOp(samplerState.depthSampleMode.value);
  1014. } else {
  1015. samplerInfo.compareEnable = VK_FALSE;
  1016. samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
  1017. }
  1018. samplerInfo.mipmapMode = Vulkan::getMipMapMode(samplerState.mipmapFilter);
  1019. samplerInfo.mipLodBias = samplerState.lodBias;
  1020. samplerInfo.minLod = 0.0f; // fixme: samplerState.minLod
  1021. samplerInfo.maxLod = 0.0f; // fixme: samplerState.maxLod
  1022. VkSampler sampler;
  1023. if (vkCreateSampler(device, &samplerInfo, nullptr, &sampler) != VK_SUCCESS) {
  1024. throw love::Exception("failed to create sampler");
  1025. }
  1026. return sampler;
  1027. }
  1028. VkSampler Graphics::getCachedSampler(const SamplerState& samplerState) {
  1029. auto it = samplers.find(samplerState);
  1030. if (it != samplers.end()) {
  1031. return it->second;
  1032. } else {
  1033. VkSampler sampler = createSampler(samplerState);
  1034. samplers.insert({samplerState, sampler});
  1035. return sampler;
  1036. }
  1037. }
  1038. VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration configuration) {
  1039. auto &shaderStages = configuration.shader->getShaderStages();
  1040. std::vector<VkVertexInputBindingDescription> bindingDescriptions;
  1041. std::vector<VkVertexInputAttributeDescription> attributeDescriptions;
  1042. createVulkanVertexFormat(configuration.vertexAttributes, bindingDescriptions, attributeDescriptions);
  1043. VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
  1044. vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
  1045. vertexInputInfo.vertexBindingDescriptionCount = static_cast<uint32_t>(bindingDescriptions.size());
  1046. vertexInputInfo.pVertexBindingDescriptions = bindingDescriptions.data();
  1047. vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());
  1048. vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
  1049. VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
  1050. inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
  1051. inputAssembly.topology = Vulkan::getPrimitiveTypeTopology(configuration.primitiveType);
  1052. inputAssembly.primitiveRestartEnable = VK_FALSE;
  1053. VkViewport viewport{};
  1054. viewport.x = 0.0f;
  1055. viewport.y = 0.0f;
  1056. viewport.width = configuration.viewportWidth;
  1057. viewport.height = configuration.viewportHeight;
  1058. viewport.minDepth = 0.0f;
  1059. viewport.maxDepth = 1.0f;
  1060. VkRect2D scissor{};
  1061. if (configuration.scissorRect.has_value()) {
  1062. scissor.offset.x = configuration.scissorRect.value().x;
  1063. scissor.offset.y = configuration.scissorRect.value().y;
  1064. scissor.extent.width = static_cast<uint32_t>(configuration.scissorRect.value().w);
  1065. scissor.extent.height = static_cast<uint32_t>(configuration.scissorRect.value().h);
  1066. }
  1067. else {
  1068. scissor.offset = { 0, 0 };
  1069. scissor.extent = swapChainExtent;
  1070. }
  1071. VkPipelineViewportStateCreateInfo viewportState{};
  1072. viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
  1073. viewportState.viewportCount = 1;
  1074. viewportState.pViewports = &viewport;
  1075. viewportState.scissorCount = 1;
  1076. viewportState.pScissors = &scissor;
  1077. VkPipelineRasterizationStateCreateInfo rasterizer{};
  1078. rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
  1079. rasterizer.depthClampEnable = VK_FALSE;
  1080. rasterizer.rasterizerDiscardEnable = VK_FALSE;
  1081. rasterizer.polygonMode = Vulkan::getPolygonMode(configuration.wireFrame);
  1082. rasterizer.lineWidth = 1.0f;
  1083. rasterizer.cullMode = Vulkan::getCullMode(configuration.cullmode);
  1084. rasterizer.frontFace = Vulkan::getFrontFace(configuration.winding);
  1085. rasterizer.depthBiasEnable = VK_FALSE;
  1086. rasterizer.depthBiasConstantFactor = 0.0f;
  1087. rasterizer.depthBiasClamp = 0.0f;
  1088. rasterizer.depthBiasSlopeFactor = 0.0f;
  1089. VkPipelineMultisampleStateCreateInfo multisampling{};
  1090. multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
  1091. multisampling.sampleShadingEnable = VK_FALSE;
  1092. multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
  1093. multisampling.minSampleShading = 1.0f; // Optional
  1094. multisampling.pSampleMask = nullptr; // Optional
  1095. multisampling.alphaToCoverageEnable = VK_FALSE; // Optional
  1096. multisampling.alphaToOneEnable = VK_FALSE; // Optional
  1097. VkPipelineColorBlendAttachmentState colorBlendAttachment{};
  1098. colorBlendAttachment.colorWriteMask = Vulkan::getColorMask(configuration.colorChannelMask);
  1099. colorBlendAttachment.blendEnable = Vulkan::getBool(configuration.blendState.enable);
  1100. colorBlendAttachment.srcColorBlendFactor = Vulkan::getBlendFactor(configuration.blendState.srcFactorRGB);
  1101. colorBlendAttachment.dstColorBlendFactor = Vulkan::getBlendFactor(configuration.blendState.dstFactorRGB);
  1102. colorBlendAttachment.colorBlendOp = Vulkan::getBlendOp(configuration.blendState.operationRGB);
  1103. colorBlendAttachment.srcAlphaBlendFactor = Vulkan::getBlendFactor(configuration.blendState.srcFactorA);
  1104. colorBlendAttachment.dstAlphaBlendFactor = Vulkan::getBlendFactor(configuration.blendState.dstFactorA);
  1105. colorBlendAttachment.alphaBlendOp = Vulkan::getBlendOp(configuration.blendState.operationA);
  1106. VkPipelineColorBlendStateCreateInfo colorBlending{};
  1107. colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
  1108. colorBlending.logicOpEnable = VK_FALSE;
  1109. colorBlending.logicOp = VK_LOGIC_OP_COPY;
  1110. colorBlending.attachmentCount = 1;
  1111. colorBlending.pAttachments = &colorBlendAttachment;
  1112. colorBlending.blendConstants[0] = 0.0f;
  1113. colorBlending.blendConstants[1] = 0.0f;
  1114. colorBlending.blendConstants[2] = 0.0f;
  1115. colorBlending.blendConstants[3] = 0.0f;
  1116. VkFormat framebufferOutputFormat = configuration.framebufferFormat;
  1117. VkPipelineRenderingCreateInfo pipelineRenderingCreateInfo{};
  1118. pipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
  1119. pipelineRenderingCreateInfo.colorAttachmentCount = 1;
  1120. pipelineRenderingCreateInfo.pColorAttachmentFormats = &framebufferOutputFormat;
  1121. VkGraphicsPipelineCreateInfo pipelineInfo{};
  1122. pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
  1123. pipelineInfo.stageCount = static_cast<uint32_t>(shaderStages.size());
  1124. pipelineInfo.pStages = shaderStages.data();
  1125. pipelineInfo.pVertexInputState = &vertexInputInfo;
  1126. pipelineInfo.pInputAssemblyState = &inputAssembly;
  1127. pipelineInfo.pViewportState = &viewportState;
  1128. pipelineInfo.pRasterizationState = &rasterizer;
  1129. pipelineInfo.pMultisampleState = &multisampling;
  1130. pipelineInfo.pDepthStencilState = nullptr;
  1131. pipelineInfo.pColorBlendState = &colorBlending;
  1132. pipelineInfo.pDynamicState = nullptr;
  1133. pipelineInfo.layout = configuration.shader->getGraphicsPipelineLayout();
  1134. pipelineInfo.subpass = 0;
  1135. pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
  1136. pipelineInfo.basePipelineIndex = -1;
  1137. pipelineInfo.pNext = &pipelineRenderingCreateInfo;
  1138. VkPipeline graphicsPipeline;
  1139. if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) {
  1140. throw love::Exception("failed to create graphics pipeline");
  1141. }
  1142. return graphicsPipeline;
  1143. }
  1144. void Graphics::ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration configuration) {
  1145. auto it = graphicsPipelines.find(configuration);
  1146. if (it != graphicsPipelines.end()) {
  1147. if (it->second != currentGraphicsPipeline) {
  1148. vkCmdBindPipeline(commandBuffers.at(imageIndex), VK_PIPELINE_BIND_POINT_GRAPHICS, it->second);
  1149. currentGraphicsPipeline = it->second;
  1150. }
  1151. } else {
  1152. VkPipeline pipeline = createGraphicsPipeline(configuration);
  1153. graphicsPipelines.insert({configuration, pipeline});
  1154. vkCmdBindPipeline(commandBuffers.at(imageIndex), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
  1155. currentGraphicsPipeline = pipeline;
  1156. }
  1157. }
  1158. void Graphics::createCommandPool() {
  1159. QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice);
  1160. VkCommandPoolCreateInfo poolInfo{};
  1161. poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
  1162. poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value();
  1163. poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
  1164. if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) {
  1165. throw love::Exception("failed to create command pool");
  1166. }
  1167. }
  1168. void Graphics::createCommandBuffers() {
  1169. commandBuffers.resize(swapChainImages.size());
  1170. dataTransferCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT);
  1171. VkCommandBufferAllocateInfo allocInfo{};
  1172. allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
  1173. allocInfo.commandPool = commandPool;
  1174. allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
  1175. allocInfo.commandBufferCount = (uint32_t)commandBuffers.size();
  1176. if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) {
  1177. throw love::Exception("failed to allocate command buffers");
  1178. }
  1179. VkCommandBufferAllocateInfo dataTransferAllocInfo{};
  1180. dataTransferAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
  1181. dataTransferAllocInfo.commandPool = commandPool;
  1182. dataTransferAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
  1183. dataTransferAllocInfo.commandBufferCount = (uint32_t)MAX_FRAMES_IN_FLIGHT;
  1184. if (vkAllocateCommandBuffers(device, &dataTransferAllocInfo, dataTransferCommandBuffers.data()) != VK_SUCCESS) {
  1185. throw love::Exception("failed to allocate data transfer command buffers");
  1186. }
  1187. }
  1188. void Graphics::createSyncObjects() {
  1189. imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
  1190. renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
  1191. inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
  1192. imagesInFlight.resize(swapChainImages.size(), VK_NULL_HANDLE);
  1193. VkSemaphoreCreateInfo semaphoreInfo{};
  1194. semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
  1195. VkFenceCreateInfo fenceInfo{};
  1196. fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
  1197. fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
  1198. for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
  1199. if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores.at(i)) != VK_SUCCESS ||
  1200. vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores.at(i)) != VK_SUCCESS ||
  1201. vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences.at(i)) != VK_SUCCESS) {
  1202. throw love::Exception("failed to create synchronization objects for a frame!");
  1203. }
  1204. }
  1205. }
  1206. void Graphics::createDefaultTexture() {
  1207. Texture::Settings settings;
  1208. standardTexture.reset((Texture*)newTexture(settings));
  1209. }
  1210. void Graphics::cleanup() {
  1211. delete quadIndexBuffer;
  1212. quadIndexBuffer = nullptr;
  1213. cleanupSwapChain();
  1214. for (auto &cleanUpFns : cleanUpFunctions) {
  1215. for (auto &cleanUpFn : cleanUpFns) {
  1216. cleanUpFn();
  1217. }
  1218. }
  1219. cleanUpFunctions.clear();
  1220. vmaDestroyAllocator(vmaAllocator);
  1221. batchedDrawBuffers.clear();
  1222. for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
  1223. vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);
  1224. vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
  1225. vkDestroyFence(device, inFlightFences[i], nullptr);
  1226. }
  1227. vkFreeCommandBuffers(device, commandPool, static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());
  1228. vkFreeCommandBuffers(device, commandPool, MAX_FRAMES_IN_FLIGHT, dataTransferCommandBuffers.data());
  1229. for (auto const& p : samplers) {
  1230. vkDestroySampler(device, p.second, nullptr);
  1231. }
  1232. samplers.clear();
  1233. // fixme: maybe we should clean up some pipelines if they haven't been used in a while.
  1234. for (auto const& p : graphicsPipelines) {
  1235. vkDestroyPipeline(device, p.second, nullptr);
  1236. }
  1237. graphicsPipelines.clear();
  1238. vkDestroyCommandPool(device, commandPool, nullptr);
  1239. vkDestroyDevice(device, nullptr);
  1240. vkDestroySurfaceKHR(instance, surface, nullptr);
  1241. vkDestroyInstance(instance, nullptr);
  1242. }
  1243. void Graphics::cleanupSwapChain() {
  1244. for (size_t i = 0; i < swapChainImageViews.size(); i++) {
  1245. vkDestroyImageView(device, swapChainImageViews[i], nullptr);
  1246. }
  1247. vkDestroySwapchainKHR(device, swapChain, nullptr);
  1248. }
  1249. void Graphics::recreateSwapChain() {
  1250. vkDeviceWaitIdle(device);
  1251. cleanupSwapChain();
  1252. createSwapChain();
  1253. createImageViews();
  1254. }
  1255. love::graphics::Graphics* createInstance() {
  1256. love::graphics::Graphics* instance = nullptr;
  1257. try {
  1258. instance = new Graphics();
  1259. }
  1260. catch (love::Exception& e) {
  1261. printf("Cannot create Vulkan renderer: %s\n", e.what());
  1262. }
  1263. return instance;
  1264. }
  1265. } // vulkan
  1266. } // graphics
  1267. } // love