diff --git a/src/common/math.h b/src/common/math.h index bc956dcb7..f56e0fc81 100644 --- a/src/common/math.h +++ b/src/common/math.h @@ -70,10 +70,6 @@ struct Rect { return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h; } - - bool operator != (const Rect& rhs) const { - return !(*this == rhs); - } }; inline int nextP2(int x) diff --git a/src/common/runtime.h b/src/common/runtime.h index 6f3dee5ae..4592e7bec 100644 --- a/src/common/runtime.h +++ b/src/common/runtime.h @@ -673,8 +673,7 @@ int luax_catchexcept(lua_State *L, const T& func) catch (const std::exception &e) { should_error = true; - const char* msg = e.what(); - lua_pushstring(L, msg); + lua_pushstring(L, e.what()); } if (should_error) diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index ace4c02b1..8184823cd 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -49,7 +49,7 @@ static const char global_syntax[] = R"( #define mediump #define highp #endif -#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH) || defined(USE_VULKAN) +#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH) #define LOVE_HIGHP_OR_MEDIUMP highp #else #define LOVE_HIGHP_OR_MEDIUMP mediump @@ -248,8 +248,8 @@ LOVE_IO_LOCATION(0) attribute vec4 VertexPosition; LOVE_IO_LOCATION(1) attribute vec4 VertexTexCoord; LOVE_IO_LOCATION(2) attribute vec4 VertexColor; -LOVE_IO_LOCATION(0) varying vec4 VaryingTexCoord; -LOVE_IO_LOCATION(1) varying vec4 VaryingColor; +varying vec4 VaryingTexCoord; +varying vec4 VaryingColor; vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition); @@ -316,8 +316,8 @@ static const char pixel_main[] = R"( #endif uniform sampler2D MainTex; -LOVE_IO_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord; -LOVE_IO_LOCATION(1) varying mediump vec4 VaryingColor; +varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord; +varying mediump vec4 VaryingColor; vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord); @@ -351,8 +351,8 @@ static const char pixel_main_custom[] = R"( #define LOVE_MULTI_CANVASES 1 #endif -LOVE_IO_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord; -LOVE_IO_LOCATION(1) varying mediump vec4 VaryingColor; +varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord; +varying mediump vec4 VaryingColor; void effect(); @@ -574,8 +574,7 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStageType stage, ss << ((!gles && (lang == Shader::LANGUAGE_GLSL1 || glsl1on3)) ? "#line 0\n" : "#line 1\n"); ss << code; - auto result = ss.str(); - return result; + return ss.str(); } Shader::Shader(StrongRef _stages[]) @@ -877,8 +876,7 @@ bool Shader::validateInternal(StrongRef stages[], std::string &err, { LocalUniform u = {}; auto &values = u.initializerValues; - // const glslang::TConstUnionArray *constarray = info.getConstArray(); was this function deprecated in a later version? - const glslang::TConstUnionArray* constarray = nullptr; + const glslang::TConstUnionArray *constarray = info.getConstArray(); // Store initializer values for local uniforms. Some love graphics // backends strip these out of the shader so we need to be able to diff --git a/src/modules/graphics/ShaderStage.cpp b/src/modules/graphics/ShaderStage.cpp index 650e5f966..a035481f8 100644 --- a/src/modules/graphics/ShaderStage.cpp +++ b/src/modules/graphics/ShaderStage.cpp @@ -18,8 +18,6 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#include - #include "ShaderStage.h" #include "common/Exception.h" #include "Graphics.h" @@ -178,8 +176,7 @@ ShaderStage::ShaderStage(Graphics *gfx, ShaderStageType stage, const std::string std::string err = "Error validating " + std::string(stagename) + " shader:\n\n" + std::string(glslangShader->getInfoLog()) + "\n" - + std::string(glslangShader->getInfoDebugLog()) + "\n\nShader Code:\n" - + glsl; + + std::string(glslangShader->getInfoDebugLog()); delete glslangShader; throw love::Exception("%s", err.c_str()); diff --git a/src/modules/graphics/opengl/Texture.h b/src/modules/graphics/opengl/Texture.h index 4e688752c..34f8d5e70 100644 --- a/src/modules/graphics/opengl/Texture.h +++ b/src/modules/graphics/opengl/Texture.h @@ -46,8 +46,8 @@ public: bool loadVolatile() override; void unloadVolatile() override; - void copyFromBuffer(love::graphics::Buffer* source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect& rect) override; - void copyToBuffer(love::graphics::Buffer* dest, int slice, int mipmap, const Rect& rect, size_t destoffset, int destwidth, size_t size) override; + void copyFromBuffer(love::graphics::Buffer *source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect &rect) override; + void copyToBuffer(love::graphics::Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth, size_t size) override; void setSamplerState(const SamplerState &s) override; diff --git a/src/modules/graphics/vulkan/Buffer.cpp b/src/modules/graphics/vulkan/Buffer.cpp index 14480c8a3..a57288a65 100644 --- a/src/modules/graphics/vulkan/Buffer.cpp +++ b/src/modules/graphics/vulkan/Buffer.cpp @@ -1,12 +1,17 @@ #include "Buffer.h" #include "Graphics.h" -namespace love { -namespace graphics { -namespace vulkan { +namespace love +{ +namespace graphics +{ +namespace vulkan +{ -static VkBufferUsageFlags getUsageBit(BufferUsage mode) { - switch (mode) { +static VkBufferUsageFlags getUsageBit(BufferUsage mode) +{ + switch (mode) + { case BUFFERUSAGE_VERTEX: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; case BUFFERUSAGE_INDEX: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT; case BUFFERUSAGE_UNIFORM: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; @@ -15,35 +20,37 @@ static VkBufferUsageFlags getUsageBit(BufferUsage mode) { } } -static VkBufferUsageFlags getVulkanUsageFlags(BufferUsageFlags flags) { +static VkBufferUsageFlags getVulkanUsageFlags(BufferUsageFlags flags) +{ VkBufferUsageFlags vkFlags = 0; - for (int i = 0; i < BUFFERUSAGE_MAX_ENUM; i++) { + for (int i = 0; i < BUFFERUSAGE_MAX_ENUM; i++) + { BufferUsageFlags flag = static_cast(1u << i); - if (flags & flag) { + if (flags & flag) vkFlags |= getUsageBit((BufferUsage)i); - } } return vkFlags; } -Buffer::Buffer(love::graphics::Graphics* gfx, const Settings& settings, const std::vector& format, const void* data, size_t size, size_t arraylength) - : love::graphics::Buffer(gfx, settings, format, size, arraylength), usageFlags(settings.usageFlags), gfx(gfx) { +Buffer::Buffer(love::graphics::Graphics *gfx, const Settings &settings, const std::vector &format, const void *data, size_t size, size_t arraylength) + : love::graphics::Buffer(gfx, settings, format, size, arraylength) + , usageFlags(settings.usageFlags) + , vgfx(dynamic_cast(gfx)) +{ loadVolatile(); } -bool Buffer::loadVolatile() { - Graphics* vgfx = (Graphics*)gfx; +bool Buffer::loadVolatile() +{ allocator = vgfx->getVmaAllocator(); VkBufferCreateInfo bufferInfo{}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = getSize(); - if (dataUsage == BUFFERDATAUSAGE_READBACK) { + if (dataUsage == BUFFERDATAUSAGE_READBACK) bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; - } - else { + else bufferInfo.usage = getVulkanUsageFlags(usageFlags); - } VmaAllocationCreateInfo allocCreateInfo = {}; allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; @@ -54,11 +61,11 @@ bool Buffer::loadVolatile() { return true; } -void Buffer::unloadVolatile() { +void Buffer::unloadVolatile() +{ if (buffer == VK_NULL_HANDLE) return; - Graphics* vgfx = (Graphics*)gfx; auto device = vgfx->getDevice(); vgfx->queueCleanUp( @@ -70,29 +77,43 @@ void Buffer::unloadVolatile() { buffer = VK_NULL_HANDLE; } -Buffer::~Buffer() { +Buffer::~Buffer() +{ unloadVolatile(); } -void* Buffer::map(MapType map, size_t offset, size_t size) { +ptrdiff_t Buffer::getHandle() const +{ + return (ptrdiff_t) buffer; +} + +ptrdiff_t Buffer::getTexelBufferHandle() const +{ + throw love::Exception("unimplemented Buffer::getTexelBufferHandle"); + return (ptrdiff_t) nullptr; // todo ? +} + +void* Buffer::map(MapType map, size_t offset, size_t size) +{ char* data = (char*)allocInfo.pMappedData; return (void*) (data + offset); } -bool Buffer::fill(size_t offset, size_t size, const void *data) { +bool Buffer::fill(size_t offset, size_t size, const void *data) +{ void* dst = (void*)((char*)allocInfo.pMappedData + offset); memcpy(dst, data, size); return true; } -void Buffer::unmap(size_t usedoffset, size_t usedsize) { +void Buffer::unmap(size_t usedoffset, size_t usedsize) +{ (void)usedoffset; (void)usedsize; } -void Buffer::copyTo(love::graphics::Buffer* dest, size_t sourceoffset, size_t destoffset, size_t size) { - Graphics* vgfx = (Graphics*)gfx; - +void Buffer::copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size) +{ auto commandBuffer = vgfx->getReadbackCommandBuffer(); VkBufferCopy bufferCopy{}; diff --git a/src/modules/graphics/vulkan/Buffer.h b/src/modules/graphics/vulkan/Buffer.h index a273d7aba..5c5212534 100644 --- a/src/modules/graphics/vulkan/Buffer.h +++ b/src/modules/graphics/vulkan/Buffer.h @@ -1,5 +1,4 @@ -#ifndef LOVE_GRAPHICS_VULKAN_BUFFER_H -#define LOVE_GRAPHICS_VULKAN_BUFFER_H +#pragma once #include "graphics/Buffer.h" #include "graphics/Volatile.h" @@ -7,40 +6,43 @@ #include "VulkanWrapper.h" -namespace love { -namespace graphics { -namespace vulkan { -class Buffer : public love::graphics::Buffer, public Volatile { +namespace love +{ +namespace graphics +{ +namespace vulkan +{ + +class Graphics; + +class Buffer + : public love::graphics::Buffer + , public Volatile +{ public: - Buffer(love::graphics::Graphics* gfx, const Settings& settings, const std::vector& format, const void* data, size_t size, size_t arraylength); + Buffer(love::graphics::Graphics *gfx, const Settings& settings, const std::vector &format, const void *data, size_t size, size_t arraylength); virtual ~Buffer(); virtual bool loadVolatile() override; virtual void unloadVolatile() override; - void* map(MapType map, size_t offset, size_t size) override; + void *map(MapType map, size_t offset, size_t size) override; void unmap(size_t usedoffset, size_t usedsize) override; - bool fill(size_t offset, size_t size, const void* data) override; - void copyTo(love::graphics::Buffer* dest, size_t sourceoffset, size_t destoffset, size_t size) override; - ptrdiff_t getHandle() const override { - return (ptrdiff_t) buffer; // todo ? - } - ptrdiff_t getTexelBufferHandle() const override { - throw love::Exception("unimplemented Buffer::getTexelBufferHandle"); - return (ptrdiff_t) nullptr; // todo ? - } + bool fill(size_t offset, size_t size, const void *data) override; + void copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size) override; + ptrdiff_t getHandle() const override; + ptrdiff_t getTexelBufferHandle() const override; private: // todo use a staging buffer for improved performance VkBuffer buffer = VK_NULL_HANDLE; - love::graphics::Graphics* gfx; + Graphics *vgfx = nullptr; VmaAllocator allocator; VmaAllocation allocation; VmaAllocationInfo allocInfo; BufferUsageFlags usageFlags; }; + } // vulkan } // graphics } // love - -#endif diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index ce45f9e83..9b4529fb6 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -20,9 +20,13 @@ #include -namespace love { -namespace graphics { -namespace vulkan { +namespace love +{ +namespace graphics +{ +namespace vulkan +{ + const std::vector validationLayers = { "VK_LAYER_KHRONOS_validation" }; @@ -41,23 +45,28 @@ constexpr int MAX_FRAMES_IN_FLIGHT = 2; constexpr uint32_t vulkanApiVersion = VK_API_VERSION_1_0; -const char* Graphics::getName() const { +const char *Graphics::getName() const +{ return "love.graphics.vulkan"; } -const VkDevice Graphics::getDevice() const { +const VkDevice Graphics::getDevice() const +{ return device; } -const VkPhysicalDevice Graphics::getPhysicalDevice() const { +const VkPhysicalDevice Graphics::getPhysicalDevice() const +{ return physicalDevice; } -const VmaAllocator Graphics::getVmaAllocator() const { +const VmaAllocator Graphics::getVmaAllocator() const +{ return vmaAllocator; } -Graphics::~Graphics() { +Graphics::~Graphics() +{ // We already cleaned those up by clearing out batchedDrawBuffers. // We set them to nullptr here so the base class doesn't crash // when it tries to free this. @@ -68,18 +77,22 @@ Graphics::~Graphics() { // START OVERRIDEN FUNCTIONS -love::graphics::Texture* Graphics::newTexture(const love::graphics::Texture::Settings& settings, const love::graphics::Texture::Slices* data) { +love::graphics::Texture *Graphics::newTexture(const love::graphics::Texture::Settings &settings, const love::graphics::Texture::Slices *data) +{ return new Texture(this, settings, data); } -love::graphics::Buffer* Graphics::newBuffer(const love::graphics::Buffer::Settings& settings, const std::vector& format, const void* data, size_t size, size_t arraylength) { +love::graphics::Buffer *Graphics::newBuffer(const love::graphics::Buffer::Settings &settings, const std::vector &format, const void *data, size_t size, size_t arraylength) +{ return new Buffer(this, settings, format, data, size, arraylength); } -void Graphics::clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) { +void Graphics::clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) +{ VkClearAttachment attachment{}; - if (color.hasValue) { + if (color.hasValue) + { attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; attachment.clearValue.color.float32[0] = static_cast(color.value.r); attachment.clearValue.color.float32[1] = static_cast(color.value.g); @@ -89,11 +102,13 @@ void Graphics::clear(OptionalColorD color, OptionalInt stencil, OptionalDouble d VkClearAttachment depthStencilAttachment{}; - if (stencil.hasValue) { + if (stencil.hasValue) + { depthStencilAttachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; depthStencilAttachment.clearValue.depthStencil.stencil = static_cast(stencil.value); } - if (depth.hasValue) { + if (depth.hasValue) + { depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; depthStencilAttachment.clearValue.depthStencil.depth = static_cast(depth.value); } @@ -114,11 +129,14 @@ void Graphics::clear(OptionalColorD color, OptionalInt stencil, OptionalDouble d 1, &rect); } -void Graphics::clear(const std::vector& colors, OptionalInt stencil, OptionalDouble depth) { +void Graphics::clear(const std::vector &colors, OptionalInt stencil, OptionalDouble depth) +{ std::vector attachments; - for (const auto& color : colors) { + for (const auto &color : colors) + { VkClearAttachment attachment{}; - if (color.hasValue) { + if (color.hasValue) + { attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; attachment.clearValue.color.float32[0] = static_cast(color.value.r); attachment.clearValue.color.float32[1] = static_cast(color.value.g); @@ -130,11 +148,13 @@ void Graphics::clear(const std::vector& colors, OptionalInt sten VkClearAttachment depthStencilAttachment{}; - if (stencil.hasValue) { + if (stencil.hasValue) + { depthStencilAttachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; depthStencilAttachment.clearValue.depthStencil.stencil = static_cast(stencil.value); } - if (depth.hasValue) { + if (depth.hasValue) + { depthStencilAttachment.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; depthStencilAttachment.clearValue.depthStencil.depth = static_cast(depth.value); } @@ -149,14 +169,14 @@ void Graphics::clear(const std::vector& colors, OptionalInt sten vkCmdClearAttachments(commandBuffers[currentFrame], static_cast(attachments.size()), attachments.data(), 1, &rect); } -void Graphics::submitGpuCommands(bool present) { +void Graphics::submitGpuCommands(bool present) +{ flushBatchedDraws(); endRecordingGraphicsCommands(present); - if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) { + if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) vkWaitForFences(device, 1, &imagesInFlight.at(imageIndex), VK_TRUE, UINT64_MAX); - } imagesInFlight[imageIndex] = inFlightFences[currentFrame]; std::vector submitCommandbuffers = { @@ -171,7 +191,8 @@ void Graphics::submitGpuCommands(bool present) { VkSemaphore waitSemaphores[] = { imageAvailableSemaphores.at(currentFrame) }; VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT }; - if (imageRequested) { + if (imageRequested) + { submitInfo.waitSemaphoreCount = 1; submitInfo.pWaitSemaphores = waitSemaphores; submitInfo.pWaitDstStageMask = waitStages; @@ -185,7 +206,8 @@ void Graphics::submitGpuCommands(bool present) { VkFence fence = VK_NULL_HANDLE; - if (present) { + if (present) + { submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = signalSemaphores; @@ -193,17 +215,17 @@ void Graphics::submitGpuCommands(bool present) { fence = inFlightFences[currentFrame]; } - if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, fence) != VK_SUCCESS) { + if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, fence) != VK_SUCCESS) throw love::Exception("failed to submit draw command buffer"); - } - if (!present) { + if (!present) + { vkQueueWaitIdle(graphicsQueue); - for (auto& callbacks : readbackCallbacks) { - for (const auto& callback : callbacks) { + for (auto &callbacks : readbackCallbacks) + { + for (const auto &callback : callbacks) callback(); - } callbacks.clear(); } @@ -211,10 +233,10 @@ void Graphics::submitGpuCommands(bool present) { } } -void Graphics::present(void* screenshotCallbackdata) { - if (!isActive()) { +void Graphics::present(void *screenshotCallbackdata) +{ + if (!isActive()) return; - } submitGpuCommands(true); @@ -234,13 +256,13 @@ void Graphics::present(void* screenshotCallbackdata) { VkResult result = vkQueuePresentKHR(presentQueue, &presentInfo); - if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) { + if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) + { framebufferResized = false; recreateSwapChain(); } - else if (result != VK_SUCCESS) { + else if (result != VK_SUCCESS) throw love::Exception("failed to present swap chain image"); - } currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; @@ -249,7 +271,8 @@ void Graphics::present(void* screenshotCallbackdata) { updatedBatchedDrawBuffers(); } -void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight) { +void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight) +{ this->width = width; this->height = height; this->pixelWidth = pixelwidth; @@ -258,7 +281,8 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh resetProjection(); } -bool Graphics::setMode(void* context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) { +bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) +{ requestedMsaa = msaa; cleanUpFunctions.clear(); @@ -287,7 +311,8 @@ bool Graphics::setMode(void* context, int width, int height, int pixelwidth, int batchedDrawBuffers.clear(); batchedDrawBuffers.reserve(MAX_FRAMES_IN_FLIGHT); - for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) + { batchedDrawBuffers.emplace_back(); // Initial sizes that should be good enough for most cases. It will // resize to fit if needed, later. @@ -328,7 +353,8 @@ bool Graphics::setMode(void* context, int width, int height, int pixelwidth, int return true; } -void Graphics::initCapabilities() { +void Graphics::initCapabilities() +{ // todo capabilities.features[FEATURE_MULTI_RENDER_TARGET_FORMATS] = false; capabilities.features[FEATURE_CLAMP_ZERO] = false; @@ -373,72 +399,81 @@ void Graphics::initCapabilities() { capabilities.textureTypes[TEXTURE_CUBE] = true; } -void Graphics::getAPIStats(int& shaderswitches) const { +void Graphics::getAPIStats(int &shaderswitches) const +{ shaderswitches = static_cast(Vulkan::getNumShaderSwitches()); } -void Graphics::unSetMode() { +void Graphics::unSetMode() +{ created = false; vkDeviceWaitIdle(device); Volatile::unloadAll(); cleanup(); } -void Graphics::setActive(bool enable) { +void Graphics::setActive(bool enable) +{ flushBatchedDraws(); active = enable; } -int Graphics::getRequestedBackbufferMSAA() const { +int Graphics::getRequestedBackbufferMSAA() const +{ return requestedMsaa; } -int Graphics::getBackbufferMSAA() const { +int Graphics::getBackbufferMSAA() const +{ return static_cast(msaaSamples); } -void Graphics::setFrontFaceWinding(Winding winding) { +void Graphics::setFrontFaceWinding(Winding winding) +{ const auto& currentState = states.back(); - if (currentState.winding == winding) { + if (currentState.winding == winding) return; - } flushBatchedDraws(); states.back().winding = winding; - if (optionalDeviceFeatures.extendedDynamicState) { + if (optionalDeviceFeatures.extendedDynamicState) ext.vkCmdSetFrontFaceEXT( commandBuffers.at(currentFrame), Vulkan::getFrontFace(winding)); - } } -void Graphics::setColorMask(ColorChannelMask mask) { +void Graphics::setColorMask(ColorChannelMask mask) +{ flushBatchedDraws(); states.back().colorMask = mask; } -void Graphics::setBlendState(const BlendState& blend) { +void Graphics::setBlendState(const BlendState &blend) +{ flushBatchedDraws(); states.back().blend = blend; } -void Graphics::setPointSize(float size) { +void Graphics::setPointSize(float size) +{ if (size != states.back().pointSize) flushBatchedDraws(); states.back().pointSize = size; } -bool Graphics::usesGLSLES() const { +bool Graphics::usesGLSLES() const +{ return false; } -Graphics::RendererInfo Graphics::getRendererInfo() const { +Graphics::RendererInfo Graphics::getRendererInfo() const +{ VkPhysicalDeviceProperties deviceProperties; vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties); @@ -460,14 +495,16 @@ Graphics::RendererInfo Graphics::getRendererInfo() const { return info; } -void Graphics::draw(const DrawCommand& cmd) { +void Graphics::draw(const DrawCommand &cmd) +{ prepareDraw(*cmd.attributes, *cmd.buffers, cmd.texture, cmd.primitiveType, cmd.cullMode); vkCmdDraw(commandBuffers.at(currentFrame), static_cast(cmd.vertexCount), static_cast(cmd.instanceCount), static_cast(cmd.vertexStart), 0); drawCalls++; } -void Graphics::draw(const DrawIndexedCommand& cmd) { +void Graphics::draw(const DrawIndexedCommand &cmd) +{ prepareDraw(*cmd.attributes, *cmd.buffers, cmd.texture, cmd.primitiveType, cmd.cullMode); vkCmdBindIndexBuffer(commandBuffers.at(currentFrame), (VkBuffer)cmd.indexBuffer->getHandle(), static_cast(cmd.indexBufferOffset), Vulkan::getVulkanIndexBufferType(cmd.indexType)); @@ -475,7 +512,8 @@ void Graphics::draw(const DrawIndexedCommand& cmd) { drawCalls++; } -void Graphics::drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture) { +void Graphics::drawQuads(int start, int count, const VertexAttributes &attributes, const BufferBindings &buffers, graphics::Texture *texture) +{ const int MAX_VERTICES_PER_DRAW = LOVE_UINT16_MAX; const int MAX_QUADS_PER_DRAW = MAX_VERTICES_PER_DRAW / 4; @@ -485,7 +523,8 @@ void Graphics::drawQuads(int start, int count, const VertexAttributes& attribute int baseVertex = start * 4; - for (int quadindex = 0; quadindex < count; quadindex += MAX_QUADS_PER_DRAW) { + for (int quadindex = 0; quadindex < count; quadindex += MAX_QUADS_PER_DRAW) + { int quadcount = std::min(MAX_QUADS_PER_DRAW, count - quadindex); vkCmdDrawIndexed(commandBuffers.at(currentFrame), static_cast(quadcount * 6), 1, 0, baseVertex, 0); @@ -495,7 +534,8 @@ void Graphics::drawQuads(int start, int count, const VertexAttributes& attribute } } -void Graphics::setColor(Colorf c) { +void Graphics::setColor(Colorf c) +{ c.r = std::min(std::max(c.r, 0.0f), 1.0f); c.g = std::min(std::max(c.g, 0.0f), 1.0f); c.b = std::min(std::max(c.b, 0.0f), 1.0f); @@ -504,7 +544,8 @@ void Graphics::setColor(Colorf c) { states.back().color = c; } -static VkRect2D computeScissor(const Rect& r, double bufferWidth, double bufferHeight, double dpiScale, VkSurfaceTransformFlagBitsKHR preTransform) { +static VkRect2D computeScissor(const Rect &r, double bufferWidth, double bufferHeight, double dpiScale, VkSurfaceTransformFlagBitsKHR preTransform) +{ double x = static_cast(r.x) * dpiScale; double y = static_cast(r.y) * dpiScale; double w = static_cast(r.w) * dpiScale; @@ -512,7 +553,8 @@ static VkRect2D computeScissor(const Rect& r, double bufferWidth, double bufferH double scissorX, scissorY, scissorW, scissorH; - switch (preTransform) { + switch (preTransform) + { case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: scissorX = bufferWidth - h - y; scissorY = x; @@ -546,7 +588,8 @@ static VkRect2D computeScissor(const Rect& r, double bufferWidth, double bufferH return scissor; } -void Graphics::setScissor(const Rect& rect) { +void Graphics::setScissor(const Rect &rect) +{ flushBatchedDraws(); VkRect2D scissor = computeScissor(rect, @@ -560,7 +603,8 @@ void Graphics::setScissor(const Rect& rect) { states.back().scissorRect = rect; } -void Graphics::setScissor() { +void Graphics::setScissor() +{ flushBatchedDraws(); states.back().scissor = false; @@ -572,20 +616,20 @@ void Graphics::setScissor() { vkCmdSetScissor(commandBuffers.at(currentFrame), 0, 1, &scissor); } -void Graphics::setStencilMode(StencilAction action, CompareMode compare, int value, love::uint32 readmask, love::uint32 writemask) { +void Graphics::setStencilMode(StencilAction action, CompareMode compare, int value, love::uint32 readmask, love::uint32 writemask) +{ flushBatchedDraws(); vkCmdSetStencilWriteMask(commandBuffers.at(currentFrame), VK_STENCIL_FACE_FRONT_AND_BACK, writemask); vkCmdSetStencilCompareMask(commandBuffers.at(currentFrame), VK_STENCIL_FACE_FRONT_AND_BACK, readmask); vkCmdSetStencilReference(commandBuffers.at(currentFrame), VK_STENCIL_FACE_FRONT_AND_BACK, value); - if (optionalDeviceFeatures.extendedDynamicState) { + if (optionalDeviceFeatures.extendedDynamicState) ext.vkCmdSetStencilOpEXT( commandBuffers.at(currentFrame), VK_STENCIL_FACE_FRONT_AND_BACK, VK_STENCIL_OP_KEEP, Vulkan::getStencilOp(action), VK_STENCIL_OP_KEEP, Vulkan::getCompareOp(compare)); - } states.back().stencil.action = action; states.back().stencil.compare = compare; @@ -594,10 +638,12 @@ void Graphics::setStencilMode(StencilAction action, CompareMode compare, int val states.back().stencil.writeMask = writemask; } -void Graphics::setDepthMode(CompareMode compare, bool write) { +void Graphics::setDepthMode(CompareMode compare, bool write) +{ flushBatchedDraws(); - if (optionalDeviceFeatures.extendedDynamicState) { + if (optionalDeviceFeatures.extendedDynamicState) + { ext.vkCmdSetDepthCompareOpEXT( commandBuffers.at(currentFrame), Vulkan::getCompareOp(compare)); @@ -609,21 +655,22 @@ void Graphics::setDepthMode(CompareMode compare, bool write) { states.back().depthWrite = write; } -void Graphics::setWireframe(bool enable) { +void Graphics::setWireframe(bool enable) +{ flushBatchedDraws(); states.back().wireframe = enable; } -PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const { - switch (format) { +PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const +{ + switch (format) + { case PIXELFORMAT_NORMAL: - if (isGammaCorrect()) { + if (isGammaCorrect()) return PIXELFORMAT_RGBA8_UNORM_sRGB; - } - else { + else return PIXELFORMAT_RGBA8_UNORM; - } case PIXELFORMAT_HDR: return PIXELFORMAT_RGBA16_FLOAT; default: @@ -631,35 +678,43 @@ PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool } } -bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) { +bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) +{ return true; } -Renderer Graphics::getRenderer() const { +Renderer Graphics::getRenderer() const +{ return RENDERER_VULKAN; } -graphics::GraphicsReadback* Graphics::newReadbackInternal(ReadbackMethod method, love::graphics::Buffer* buffer, size_t offset, size_t size, data::ByteData* dest, size_t destoffset) { +graphics::GraphicsReadback *Graphics::newReadbackInternal(ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset) +{ return new GraphicsReadback(this, method, buffer, offset, size, dest, destoffset); } -graphics::GraphicsReadback* Graphics::newReadbackInternal(ReadbackMethod method, love::graphics::Texture* texture, int slice, int mipmap, const Rect& rect, image::ImageData* dest, int destx, int desty) { +graphics::GraphicsReadback *Graphics::newReadbackInternal(ReadbackMethod method, love::graphics::Texture *texture, int slice, int mipmap, const Rect &rect, image::ImageData *dest, int destx, int desty) +{ return new GraphicsReadback(this, method, texture, slice, mipmap, rect, dest, destx, desty); } -graphics::ShaderStage* Graphics::newShaderStageInternal(ShaderStageType stage, const std::string& cachekey, const std::string& source, bool gles) { +graphics::ShaderStage *Graphics::newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles) +{ return new ShaderStage(this, stage, source, gles, cachekey); } -graphics::Shader* Graphics::newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) { +graphics::Shader *Graphics::newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) +{ return new Shader(stages); } -graphics::StreamBuffer* Graphics::newStreamBuffer(BufferUsage type, size_t size) { +graphics::StreamBuffer *Graphics::newStreamBuffer(BufferUsage type, size_t size) +{ return new StreamBuffer(this, type, size); } -bool Graphics::dispatch(int x, int y, int z) { +bool Graphics::dispatch(int x, int y, int z) +{ vkCmdBindPipeline(computeCommandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_COMPUTE, computeShader->getComputePipeline()); computeShader->cmdPushDescriptorSets(computeCommandBuffers.at(currentFrame), currentFrame, VK_PIPELINE_BIND_POINT_COMPUTE); @@ -669,30 +724,31 @@ bool Graphics::dispatch(int x, int y, int z) { return true; } -Matrix4 Graphics::computeDeviceProjection(const Matrix4& projection, bool rendertotexture) const { +Matrix4 Graphics::computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const +{ uint32 flags = DEVICE_PROJECTION_DEFAULT; return calculateDeviceProjection(projection, flags); } -void Graphics::setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) { +void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture) +{ endRenderPass(); bool isWindow = rts.getFirstTarget().texture == nullptr; - if (isWindow) { + if (isWindow) startDefaultRenderPass(); - } else { + else startRenderPass(rts, pixelw, pixelh, hasSRGBtexture); - } } // END IMPLEMENTATION OVERRIDDEN FUNCTIONS -void Graphics::initDynamicState() { - if (states.back().scissor) { +void Graphics::initDynamicState() +{ + if (states.back().scissor) setScissor(states.back().scissorRect); - } else { + else setScissor(); - } VkViewport viewport{}; viewport.x = 0.0f; @@ -708,7 +764,8 @@ void Graphics::initDynamicState() { vkCmdSetStencilCompareMask(commandBuffers.at(currentFrame), VK_STENCIL_FACE_FRONT_AND_BACK, states.back().stencil.readMask); vkCmdSetStencilReference(commandBuffers.at(currentFrame), VK_STENCIL_FACE_FRONT_AND_BACK, states.back().stencil.value); - if (optionalDeviceFeatures.extendedDynamicState) { + if (optionalDeviceFeatures.extendedDynamicState) + { ext.vkCmdSetStencilOpEXT( commandBuffers.at(currentFrame), VK_STENCIL_FACE_FRONT_AND_BACK, @@ -726,32 +783,31 @@ void Graphics::initDynamicState() { } } -void Graphics::beginFrame() { +void Graphics::beginFrame() +{ vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX); - while (true) { + while (true) + { VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); if (result == VK_ERROR_OUT_OF_DATE_KHR) { recreateSwapChain(); continue; } - else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { + else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) throw love::Exception("failed to acquire swap chain image"); - } break; } imageRequested = true; - for (auto& readbackCallback : readbackCallbacks.at(currentFrame)) { + for (auto& readbackCallback : readbackCallbacks.at(currentFrame)) readbackCallback(); - } readbackCallbacks.at(currentFrame).clear(); - for (auto& cleanUpFn : cleanUpFunctions.at(currentFrame)) { + for (auto& cleanUpFn : cleanUpFunctions.at(currentFrame)) cleanUpFn(); - } cleanUpFunctions.at(currentFrame).clear(); startRecordingGraphicsCommands(true); @@ -759,30 +815,26 @@ void Graphics::beginFrame() { Vulkan::resetShaderSwitches(); } -void Graphics::startRecordingGraphicsCommands(bool newFrame) { +void Graphics::startRecordingGraphicsCommands(bool newFrame) +{ VkCommandBufferBeginInfo beginInfo{}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; beginInfo.pInheritanceInfo = nullptr; - if (vkBeginCommandBuffer(commandBuffers.at(currentFrame), &beginInfo) != VK_SUCCESS) { + if (vkBeginCommandBuffer(commandBuffers.at(currentFrame), &beginInfo) != VK_SUCCESS) throw love::Exception("failed to begin recording command buffer"); - } - if (vkBeginCommandBuffer(dataTransferCommandBuffers.at(currentFrame), &beginInfo) != VK_SUCCESS) { + if (vkBeginCommandBuffer(dataTransferCommandBuffers.at(currentFrame), &beginInfo) != VK_SUCCESS) throw love::Exception("failed to begin recording data transfer command buffer"); - } - if (vkBeginCommandBuffer(readbackCommandBuffers.at(currentFrame), &beginInfo) != VK_SUCCESS) { + if (vkBeginCommandBuffer(readbackCommandBuffers.at(currentFrame), &beginInfo) != VK_SUCCESS) throw love::Exception("failed to begin recording readback command buffer"); - } - if (vkBeginCommandBuffer(computeCommandBuffers.at(currentFrame), &beginInfo) != VK_SUCCESS) { + if (vkBeginCommandBuffer(computeCommandBuffers.at(currentFrame), &beginInfo) != VK_SUCCESS) throw love::Exception("failed to begin recording compute command buffer"); - } initDynamicState(); - if (newFrame) { + if (newFrame) Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), swapChainImages[imageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - } startDefaultRenderPass(); } @@ -790,25 +842,21 @@ void Graphics::startRecordingGraphicsCommands(bool newFrame) { void Graphics::endRecordingGraphicsCommands(bool present) { endRenderPass(); - if (present) { + if (present) Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), swapChainImages[imageIndex], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); - } - if (vkEndCommandBuffer(commandBuffers.at(currentFrame)) != VK_SUCCESS) { + if (vkEndCommandBuffer(commandBuffers.at(currentFrame)) != VK_SUCCESS) throw love::Exception("failed to record command buffer"); - } - if (vkEndCommandBuffer(dataTransferCommandBuffers.at(currentFrame)) != VK_SUCCESS) { + if (vkEndCommandBuffer(dataTransferCommandBuffers.at(currentFrame)) != VK_SUCCESS) throw love::Exception("failed to record data transfer command buffer"); - } - if (vkEndCommandBuffer(readbackCommandBuffers.at(currentFrame)) != VK_SUCCESS) { + if (vkEndCommandBuffer(readbackCommandBuffers.at(currentFrame)) != VK_SUCCESS) throw love::Exception("failed to record read back command buffer"); - } - if (vkEndCommandBuffer(computeCommandBuffers.at(currentFrame)) != VK_SUCCESS) { + if (vkEndCommandBuffer(computeCommandBuffers.at(currentFrame)) != VK_SUCCESS) throw love::Exception("failed to record compute command buffer"); - } } -void Graphics::updatedBatchedDrawBuffers() { +void Graphics::updatedBatchedDrawBuffers() +{ batchedDrawState.vb[0] = batchedDrawBuffers[currentFrame].vertexBuffer1; batchedDrawState.vb[0]->nextFrame(); batchedDrawState.vb[1] = batchedDrawBuffers[currentFrame].vertexBuffer2; @@ -817,27 +865,33 @@ void Graphics::updatedBatchedDrawBuffers() { batchedDrawState.indexBuffer->nextFrame(); } -uint32_t Graphics::getNumImagesInFlight() const { +uint32_t Graphics::getNumImagesInFlight() const +{ return MAX_FRAMES_IN_FLIGHT; } -const VkDeviceSize Graphics::getMinUniformBufferOffsetAlignment() const { +const VkDeviceSize Graphics::getMinUniformBufferOffsetAlignment() const +{ return minUniformBufferOffsetAlignment; } -graphics::Texture* Graphics::getDefaultTexture() const { +graphics::Texture *Graphics::getDefaultTexture() const +{ return dynamic_cast(standardTexture.get()); } -VkCommandBuffer Graphics::getDataTransferCommandBuffer() { +VkCommandBuffer Graphics::getDataTransferCommandBuffer() +{ return dataTransferCommandBuffers.at(currentFrame); } -VkCommandBuffer Graphics::getReadbackCommandBuffer() { +VkCommandBuffer Graphics::getReadbackCommandBuffer() +{ return readbackCommandBuffers.at(currentFrame); } -void Graphics::oneTimeCommand(std::function cmd) { +void Graphics::oneTimeCommand(std::function cmd) +{ VkCommandBufferAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.commandPool = commandPool; @@ -845,60 +899,57 @@ void Graphics::oneTimeCommand(std::function cmd) { allocInfo.commandBufferCount = 1; VkCommandBuffer commandBuffer; - if (vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer) != VK_SUCCESS) { + if (vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer) != VK_SUCCESS) throw love::Exception("failed to allocate one time command buffer"); - } VkCommandBufferBeginInfo beginInfo{}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) { + if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) throw love::Exception("failed to start recording one time command buffer"); - } cmd(commandBuffer); - if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) { + if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) throw love::Exception("failed to end recording one time command buffer"); - } VkSubmitInfo submitInfo{}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &commandBuffer; - if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) { + if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) != VK_SUCCESS) throw love::Exception("failed to submit to queue"); - } - if (vkQueueWaitIdle(graphicsQueue) != VK_SUCCESS) { + if (vkQueueWaitIdle(graphicsQueue) != VK_SUCCESS) throw love::Exception("failed to wait for queue idle"); - } vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); } -void Graphics::queueCleanUp(std::function cleanUp) { +void Graphics::queueCleanUp(std::function cleanUp) +{ cleanUpFunctions.at(currentFrame).push_back(cleanUp); } -void Graphics::addReadbackCallback(std::function callback) { +void Graphics::addReadbackCallback(std::function callback) +{ readbackCallbacks.at(currentFrame).push_back(callback); } -graphics::Shader::BuiltinUniformData Graphics::getCurrentBuiltinUniformData() { +graphics::Shader::BuiltinUniformData Graphics::getCurrentBuiltinUniformData() +{ love::graphics::Shader::BuiltinUniformData data; data.transformMatrix = getTransform(); - data.projectionMatrix = getDeviceProjection(); - data.projectionMatrix = displayRotation * data.projectionMatrix ; + data.projectionMatrix = displayRotation * getDeviceProjection(); // The normal matrix is the transpose of the inverse of the rotation portion // (top-left 3x3) of the transform matrix. { Matrix3 normalmatrix = Matrix3(data.transformMatrix).transposedInverse(); - const float* e = normalmatrix.getElements(); + const float *e = normalmatrix.getElements(); for (int i = 0; i < 3; i++) { data.normalMatrix[i].x = e[i * 3 + 0]; @@ -926,7 +977,8 @@ graphics::Shader::BuiltinUniformData Graphics::getCurrentBuiltinUniformData() { return data; } -static void checkOptionalInstanceExtensions(OptionalInstanceExtensions& ext) { +static void checkOptionalInstanceExtensions(OptionalInstanceExtensions &ext) +{ uint32_t count; vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr); @@ -935,17 +987,15 @@ static void checkOptionalInstanceExtensions(OptionalInstanceExtensions& ext) { vkEnumerateInstanceExtensionProperties(nullptr, &count, extensions.data()); - for (const auto& extension : extensions) { - if (strcmp(extension.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0) { + for (const auto& extension : extensions) + if (strcmp(extension.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0) ext.physicalDeviceProperties2 = true; - } - } } -void Graphics::createVulkanInstance() { - if (enableValidationLayers && !checkValidationSupport()) { +void Graphics::createVulkanInstance() +{ + if (enableValidationLayers && !checkValidationSupport()) throw love::Exception("validation layers requested, but not available"); - } VkApplicationInfo appInfo{}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; @@ -961,101 +1011,96 @@ void Graphics::createVulkanInstance() { createInfo.pNext = nullptr; auto window = Module::getInstance(M_WINDOW); - const void* handle = window->getHandle(); + const void *handle = window->getHandle(); unsigned int count; - if (SDL_Vulkan_GetInstanceExtensions((SDL_Window*)handle, &count, nullptr) != SDL_TRUE) { + if (SDL_Vulkan_GetInstanceExtensions((SDL_Window*)handle, &count, nullptr) != SDL_TRUE) throw love::Exception("couldn't retrieve sdl vulkan extensions"); - } std::vector extensions = {}; checkOptionalInstanceExtensions(optionalInstanceExtensions); - if (optionalInstanceExtensions.physicalDeviceProperties2) { + if (optionalInstanceExtensions.physicalDeviceProperties2) extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); - } size_t additional_extension_count = extensions.size(); extensions.resize(additional_extension_count + count); - if (SDL_Vulkan_GetInstanceExtensions((SDL_Window*)handle, &count, extensions.data() + additional_extension_count) != SDL_TRUE) { + if (SDL_Vulkan_GetInstanceExtensions((SDL_Window*)handle, &count, extensions.data() + additional_extension_count) != SDL_TRUE) throw love::Exception("couldn't retrieve sdl vulkan extensions"); - } createInfo.enabledExtensionCount = static_cast(extensions.size()); createInfo.ppEnabledExtensionNames = extensions.data(); - if (enableValidationLayers) { + if (enableValidationLayers) + { createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } - else { + else + { createInfo.enabledLayerCount = 0; createInfo.ppEnabledLayerNames = nullptr; } - if (vkCreateInstance( - &createInfo, - nullptr, - &instance) != VK_SUCCESS) { + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) throw love::Exception("couldn't create vulkan instance"); - } #ifdef LOVE_ANDROID volkLoadInstance(instance); #endif } -bool Graphics::checkValidationSupport() { +bool Graphics::checkValidationSupport() +{ uint32_t layerCount; vkEnumerateInstanceLayerProperties(&layerCount, nullptr); std::vector availableLayers(layerCount); vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); - for (const char* layerName : validationLayers) { + for (const char *layerName : validationLayers) + { bool layerFound = false; - for (const auto& layerProperties : availableLayers) { - if (strcmp(layerName, layerProperties.layerName) == 0) { + for (const auto &layerProperties : availableLayers) + if (strcmp(layerName, layerProperties.layerName) == 0) + { layerFound = true; break; } - } - if (!layerFound) { + if (!layerFound) return false; - } } return true; } -void Graphics::pickPhysicalDevice() { +void Graphics::pickPhysicalDevice() +{ uint32_t deviceCount = 0; vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); - if (deviceCount == 0) { + if (deviceCount == 0) throw love::Exception("failed to find GPUs with Vulkan support"); - } std::vector devices(deviceCount); vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); std::multimap candidates; - for (const auto& device : devices) { + for (const auto &device : devices) + { int score = rateDeviceSuitability(device); candidates.insert(std::make_pair(score, device)); } - if (candidates.rbegin()->first > 0) { + if (candidates.rbegin()->first > 0) physicalDevice = candidates.rbegin()->second; - } - else { + else throw love::Exception("failed to find a suitable gpu"); - } VkPhysicalDeviceProperties properties; vkGetPhysicalDeviceProperties(physicalDevice, &properties); @@ -1064,7 +1109,8 @@ void Graphics::pickPhysicalDevice() { getMaxUsableSampleCount(); } -bool Graphics::checkDeviceExtensionSupport(VkPhysicalDevice device) { +bool Graphics::checkDeviceExtensionSupport(VkPhysicalDevice device) +{ uint32_t extensionCount; vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr); @@ -1073,9 +1119,8 @@ bool Graphics::checkDeviceExtensionSupport(VkPhysicalDevice device) { std::set requiredExtensions(deviceExtensions.begin(), deviceExtensions.end()); - for (const auto& extension : availableExtensions) { + for (const auto &extension : availableExtensions) requiredExtensions.erase(extension.extensionName); - } return requiredExtensions.empty(); } @@ -1083,7 +1128,8 @@ bool Graphics::checkDeviceExtensionSupport(VkPhysicalDevice device) { // if the score is nonzero then the device is suitable. // A higher rating means generally better performance // if the score is 0 the device is unsuitable -int Graphics::rateDeviceSuitability(VkPhysicalDevice device) { +int Graphics::rateDeviceSuitability(VkPhysicalDevice device) +{ VkPhysicalDeviceProperties deviceProperties; VkPhysicalDeviceFeatures deviceFeatures; vkGetPhysicalDeviceProperties(device, &deviceProperties); @@ -1093,48 +1139,42 @@ int Graphics::rateDeviceSuitability(VkPhysicalDevice device) { // optional - if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { + if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) score += 1000; - } - if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) { + if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) score += 100; - } - if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU) { + if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU) score += 10; - } // definitely needed QueueFamilyIndices indices = findQueueFamilies(device); - if (!indices.isComplete()) { + if (!indices.isComplete()) score = 0; - } bool extensionsSupported = checkDeviceExtensionSupport(device); - if (!extensionsSupported) { + if (!extensionsSupported) score = 0; - } - if (extensionsSupported) { + if (extensionsSupported) + { auto swapChainSupport = querySwapChainSupport(device); bool swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty(); - if (!swapChainAdequate) { + if (!swapChainAdequate) score = 0; - } } - if (!deviceFeatures.samplerAnisotropy) { + if (!deviceFeatures.samplerAnisotropy) score = 0; - } - if (!deviceFeatures.fillModeNonSolid) { + if (!deviceFeatures.fillModeNonSolid) score = 0; - } return score; } -QueueFamilyIndices Graphics::findQueueFamilies(VkPhysicalDevice device) { +QueueFamilyIndices Graphics::findQueueFamilies(VkPhysicalDevice device) +{ QueueFamilyIndices indices; uint32_t queueFamilyCount = 0; @@ -1144,21 +1184,19 @@ QueueFamilyIndices Graphics::findQueueFamilies(VkPhysicalDevice device) { vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data()); int i = 0; - for (const auto& queueFamily : queueFamilies) { - if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT && queueFamily.queueFlags & VK_QUEUE_COMPUTE_BIT) { + for (const auto &queueFamily : queueFamilies) + { + if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT && queueFamily.queueFlags & VK_QUEUE_COMPUTE_BIT) indices.graphicsFamily = i; - } VkBool32 presentSupport = false; vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport); - if (presentSupport) { + if (presentSupport) indices.presentFamily = i; - } - if (indices.isComplete()) { + if (indices.isComplete()) break; - } i++; } @@ -1166,31 +1204,33 @@ QueueFamilyIndices Graphics::findQueueFamilies(VkPhysicalDevice device) { return indices; } -static void findOptionalDeviceExtensions(VkPhysicalDevice physicalDevice, OptionalDeviceFeatures &optionalDeviceFeatures) { +static void findOptionalDeviceExtensions(VkPhysicalDevice physicalDevice, OptionalDeviceFeatures &optionalDeviceFeatures) +{ uint32_t extensionCount; vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr); std::vector availableExtensions(extensionCount); vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, availableExtensions.data()); - for (const auto& extension : availableExtensions) { - if (strcmp(extension.extensionName, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) == 0) { + for (const auto& extension : availableExtensions) + { + if (strcmp(extension.extensionName, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) == 0) optionalDeviceFeatures.extendedDynamicState = true; - } - if (strcmp(extension.extensionName, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME) == 0) { + if (strcmp(extension.extensionName, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME) == 0) optionalDeviceFeatures.pushDescriptor = true; - } } } -void Graphics::createLogicalDevice() { +void Graphics::createLogicalDevice() +{ QueueFamilyIndices indices = findQueueFamilies(physicalDevice); std::vector queueCreateInfos; std::set uniqueQueueFamilies = { indices.graphicsFamily.value(), indices.presentFamily.value()}; float queuePriority = 1.0f; - for (uint32_t queueFamily : uniqueQueueFamilies) { + for (uint32_t queueFamily : uniqueQueueFamilies) + { VkDeviceQueueCreateInfo queueCreateInfo{}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.queueFamilyIndex = queueFamily; @@ -1201,9 +1241,8 @@ void Graphics::createLogicalDevice() { findOptionalDeviceExtensions(physicalDevice, optionalDeviceFeatures); - if (optionalDeviceFeatures.extendedDynamicState && !optionalInstanceExtensions.physicalDeviceProperties2) { + if (optionalDeviceFeatures.extendedDynamicState && !optionalInstanceExtensions.physicalDeviceProperties2) optionalDeviceFeatures.extendedDynamicState = false; - } VkPhysicalDeviceFeatures deviceFeatures{}; deviceFeatures.samplerAnisotropy = VK_TRUE; @@ -1225,13 +1264,13 @@ void Graphics::createLogicalDevice() { createInfo.enabledExtensionCount = static_cast(enabledExtensions.size()); createInfo.ppEnabledExtensionNames = enabledExtensions.data(); - if (enableValidationLayers) { + if (enableValidationLayers) + { createInfo.enabledLayerCount = static_cast(validationLayers.size()); createInfo.ppEnabledLayerNames = validationLayers.data(); } - else { + else createInfo.enabledLayerCount = 0; - } VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extendedDynamicStateFeatures{}; extendedDynamicStateFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; @@ -1240,9 +1279,8 @@ void Graphics::createLogicalDevice() { createInfo.pNext = &extendedDynamicStateFeatures; - if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) { + if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) throw love::Exception("failed to create logical device"); - } #ifdef LOVE_ANDROID volkLoadDevice(device); @@ -1251,7 +1289,8 @@ void Graphics::createLogicalDevice() { vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue); vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue); - if (optionalDeviceFeatures.extendedDynamicState) { + if (optionalDeviceFeatures.extendedDynamicState) + { #ifdef LOVE_ANDROID ext.vkCmdSetCullModeEXT = vkCmdSetCullModeEXT; ext.vkCmdSetDepthBoundsTestEnableEXT = vkCmdSetDepthBoundsTestEnableEXT; @@ -1278,7 +1317,8 @@ void Graphics::createLogicalDevice() { ext.vkCmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT)vkGetDeviceProcAddr(device, "vkCmdSetViewportWithCountEXT"); #endif } - if (optionalDeviceFeatures.pushDescriptor) { + if (optionalDeviceFeatures.pushDescriptor) + { #ifdef LOVE_ANDROID ext.vkCmdPushDescriptorSetKHR = vkCmdPushDescriptorSetKHR; #else @@ -1287,7 +1327,8 @@ void Graphics::createLogicalDevice() { } } -void Graphics::initVMA() { +void Graphics::initVMA() +{ VmaAllocatorCreateInfo allocatorCreateInfo = {}; allocatorCreateInfo.vulkanApiVersion = vulkanApiVersion; allocatorCreateInfo.physicalDevice = physicalDevice; @@ -1333,20 +1374,20 @@ void Graphics::initVMA() { allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions; #endif - if (vmaCreateAllocator(&allocatorCreateInfo, &vmaAllocator) != VK_SUCCESS) { + if (vmaCreateAllocator(&allocatorCreateInfo, &vmaAllocator) != VK_SUCCESS) throw love::Exception("failed to create vma allocator"); - } } -void Graphics::createSurface() { +void Graphics::createSurface() +{ auto window = Module::getInstance(M_WINDOW); const void* handle = window->getHandle(); - if (SDL_Vulkan_CreateSurface((SDL_Window*)handle, instance, &surface) != SDL_TRUE) { + if (SDL_Vulkan_CreateSurface((SDL_Window*)handle, instance, &surface) != SDL_TRUE) throw love::Exception("failed to create window surface"); - } } -SwapChainSupportDetails Graphics::querySwapChainSupport(VkPhysicalDevice device) { +SwapChainSupportDetails Graphics::querySwapChainSupport(VkPhysicalDevice device) +{ SwapChainSupportDetails details; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities); @@ -1354,7 +1395,8 @@ SwapChainSupportDetails Graphics::querySwapChainSupport(VkPhysicalDevice device) uint32_t formatCount; vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr); - if (formatCount != 0) { + if (formatCount != 0) + { details.formats.resize(formatCount); vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data()); } @@ -1362,7 +1404,8 @@ SwapChainSupportDetails Graphics::querySwapChainSupport(VkPhysicalDevice device) uint32_t presentModeCount; vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr); - if (presentModeCount != 0) { + if (presentModeCount != 0) + { details.presentModes.resize(presentModeCount); vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data()); } @@ -1370,7 +1413,8 @@ SwapChainSupportDetails Graphics::querySwapChainSupport(VkPhysicalDevice device) return details; } -void Graphics::createSwapChain() { +void Graphics::createSwapChain() +{ SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice); VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats); @@ -1378,7 +1422,8 @@ void Graphics::createSwapChain() { VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities); if (swapChainSupport.capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR || - swapChainSupport.capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { + swapChainSupport.capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) + { uint32_t width, height; width = extent.width; height = extent.height; @@ -1389,15 +1434,15 @@ void Graphics::createSwapChain() { auto currentTransform = swapChainSupport.capabilities.currentTransform; constexpr float PI = 3.14159265358979323846f; float angle = 0.0f; - if (currentTransform & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { + if (currentTransform & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) angle = 0.0f; - } else if (currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) { + else if (currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) angle = -PI / 2.0f; - } else if (currentTransform & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) { + else if (currentTransform & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) angle = -PI; - } else if (currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { + else if (currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) angle = -3.0f * PI / 2.0f; - } + float data[] = { cosf(angle), -sinf(angle), 0.0f, 0.0f, sinf(angle), cosf(angle), 0.0f, 0.0f, @@ -1407,9 +1452,8 @@ void Graphics::createSwapChain() { displayRotation = Matrix4(data); uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1; - if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) { + if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) imageCount = swapChainSupport.capabilities.maxImageCount; - } VkSwapchainCreateInfoKHR createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; @@ -1425,12 +1469,14 @@ void Graphics::createSwapChain() { QueueFamilyIndices indices = findQueueFamilies(physicalDevice); uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(), indices.presentFamily.value() }; - if (indices.graphicsFamily != indices.presentFamily) { + if (indices.graphicsFamily != indices.presentFamily) + { createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; createInfo.queueFamilyIndexCount = 2; createInfo.pQueueFamilyIndices = queueFamilyIndices; } - else { + else + { createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.queueFamilyIndexCount = 0; createInfo.pQueueFamilyIndices = nullptr; @@ -1442,9 +1488,8 @@ void Graphics::createSwapChain() { createInfo.clipped = VK_TRUE; createInfo.oldSwapchain = VK_NULL_HANDLE; - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) { + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) throw love::Exception("failed to create swap chain"); - } vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); swapChainImages.resize(imageCount); @@ -1455,57 +1500,52 @@ void Graphics::createSwapChain() { preTransform = swapChainSupport.capabilities.currentTransform; } -VkSurfaceFormatKHR Graphics::chooseSwapSurfaceFormat(const std::vector& availableFormats) { - for (const auto& availableFormat : availableFormats) { +VkSurfaceFormatKHR Graphics::chooseSwapSurfaceFormat(const std::vector &availableFormats) +{ + for (const auto& availableFormat : availableFormats) // fixme: what if this format and colorspace is not available? - if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) return availableFormat; - } - } return availableFormats[0]; } -VkPresentModeKHR Graphics::chooseSwapPresentMode(const std::vector& availablePresentModes) { +VkPresentModeKHR Graphics::chooseSwapPresentMode(const std::vector &availablePresentModes) +{ int vsync = Vulkan::getVsync(); + auto begin = availablePresentModes.begin(); + auto end = availablePresentModes.end(); + switch (vsync) { - case -1: { - auto it = std::find(availablePresentModes.begin(), availablePresentModes.end(), VK_PRESENT_MODE_FIFO_RELAXED_KHR); - if (it != availablePresentModes.end()) { + case -1: + if (std::find(begin, end, VK_PRESENT_MODE_FIFO_RELAXED_KHR) != availablePresentModes.end()) return VK_PRESENT_MODE_FIFO_RELAXED_KHR; - } - else { + else return VK_PRESENT_MODE_FIFO_KHR; - } - } - case 0: { - auto it = std::find(availablePresentModes.begin(), availablePresentModes.end(), VK_PRESENT_MODE_MAILBOX_KHR); - if (it != availablePresentModes.end()) { + case 0: + if (std::find(begin, end, VK_PRESENT_MODE_MAILBOX_KHR) != availablePresentModes.end()) return VK_PRESENT_MODE_MAILBOX_KHR; - } - else { - it = std::find(availablePresentModes.begin(), availablePresentModes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR); - if (it != availablePresentModes.end()) { + else + { + if (std::find(begin, end, VK_PRESENT_MODE_IMMEDIATE_KHR) != availablePresentModes.end()) return VK_PRESENT_MODE_IMMEDIATE_KHR; - } - else { + else return VK_PRESENT_MODE_FIFO_KHR; - } } - } default: return VK_PRESENT_MODE_FIFO_KHR; } } -VkExtent2D Graphics::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) { - if (capabilities.currentExtent.width != UINT32_MAX) { +VkExtent2D Graphics::chooseSwapExtent(const VkSurfaceCapabilitiesKHR &capabilities) +{ + if (capabilities.currentExtent.width != UINT32_MAX) return capabilities.currentExtent; - } - else { + else + { auto window = Module::getInstance(M_WINDOW); - const void* handle = window->getHandle(); + const void *handle = window->getHandle(); int width, height; SDL_Vulkan_GetDrawableSize((SDL_Window*)handle, &width, &height); @@ -1522,24 +1562,26 @@ VkExtent2D Graphics::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabiliti } } -VkCompositeAlphaFlagBitsKHR Graphics::chooseCompositeAlpha(const VkSurfaceCapabilitiesKHR &capabilities) { - if (capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) { +VkCompositeAlphaFlagBitsKHR Graphics::chooseCompositeAlpha(const VkSurfaceCapabilitiesKHR& capabilities) +{ + if (capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) return VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - } else if (capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) { + else if (capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) return VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; - } else if (capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) { + else if (capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) return VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; - } else if (capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) { + else if (capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) return VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR; - } else { + else throw love::Exception("failed to find composite alpha"); - } } -void Graphics::createImageViews() { +void Graphics::createImageViews() +{ swapChainImageViews.resize(swapChainImages.size()); - for (size_t i = 0; i < swapChainImages.size(); i++) { + for (size_t i = 0; i < swapChainImages.size(); i++) + { VkImageViewCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = swapChainImages.at(i); @@ -1555,13 +1597,13 @@ void Graphics::createImageViews() { createInfo.subresourceRange.baseArrayLayer = 0; createInfo.subresourceRange.layerCount = 1; - if (vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews.at(i)) != VK_SUCCESS) { + if (vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews.at(i)) != VK_SUCCESS) throw love::Exception("failed to create image views"); - } } } -void Graphics::createDefaultRenderPass() { +void Graphics::createDefaultRenderPass() +{ RenderPassConfiguration renderPassConfiguration{}; renderPassConfiguration.colorFormats.push_back(swapChainImageFormat); renderPassConfiguration.staticData.initialColorImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -1574,10 +1616,12 @@ void Graphics::createDefaultRenderPass() { defaultRenderPass = createRenderPass(renderPassConfiguration); } -void Graphics::createDefaultFramebuffers() { +void Graphics::createDefaultFramebuffers() +{ defaultFramebuffers.clear(); - for (const auto view : swapChainImageViews) { + for (const auto view : swapChainImageViews) + { FramebufferConfiguration configuration{}; configuration.staticData.renderPass = defaultRenderPass; configuration.staticData.width = swapChainExtent.width; @@ -1585,7 +1629,8 @@ void Graphics::createDefaultFramebuffers() { configuration.staticData.depthView = depthImageView; if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) configuration.colorViews.push_back(view); - else { + else + { configuration.colorViews.push_back(colorImageView); configuration.staticData.resolveView = view; } @@ -1593,20 +1638,18 @@ void Graphics::createDefaultFramebuffers() { } } -VkFramebuffer Graphics::createFramebuffer(FramebufferConfiguration configuration) { +VkFramebuffer Graphics::createFramebuffer(FramebufferConfiguration &configuration) +{ std::vector attachments; - for (const auto& colorView : configuration.colorViews) { + for (const auto& colorView : configuration.colorViews) attachments.push_back(colorView); - } - if (configuration.staticData.depthView) { + if (configuration.staticData.depthView) attachments.push_back(configuration.staticData.depthView); - } - if (configuration.staticData.resolveView) { + if (configuration.staticData.resolveView) attachments.push_back(configuration.staticData.resolveView); - } VkFramebufferCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; @@ -1618,29 +1661,32 @@ VkFramebuffer Graphics::createFramebuffer(FramebufferConfiguration configuration createInfo.layers = 1; VkFramebuffer frameBuffer; - if (vkCreateFramebuffer(device, &createInfo, nullptr, &frameBuffer) != VK_SUCCESS) { + if (vkCreateFramebuffer(device, &createInfo, nullptr, &frameBuffer) != VK_SUCCESS) throw love::Exception("failed to create framebuffer"); - } return frameBuffer; } -VkFramebuffer Graphics::getFramebuffer(FramebufferConfiguration configuration) { +VkFramebuffer Graphics::getFramebuffer(FramebufferConfiguration &configuration) +{ auto it = framebuffers.find(configuration); - if (it != framebuffers.end()) { + if (it != framebuffers.end()) return it->second; - } - else { + else + { VkFramebuffer framebuffer = createFramebuffer(configuration); framebuffers[configuration] = framebuffer; return framebuffer; } } -void Graphics::createDefaultShaders() { - for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++) { +void Graphics::createDefaultShaders() +{ + for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++) + { auto stype = (Shader::StandardShader)i; - if (!Shader::standardShaders[i]) { + if (!Shader::standardShaders[i]) + { std::vector stages; stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_VERTEX)); stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_PIXEL)); @@ -1649,7 +1695,8 @@ void Graphics::createDefaultShaders() { } } -VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) { +VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration) +{ VkSubpassDescription subPass{}; subPass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; @@ -1657,7 +1704,8 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) { std::vector colorAttachmentRefs; uint32_t attachment = 0; - for (const auto& colorFormat : configuration.colorFormats) { + for (const auto& colorFormat : configuration.colorFormats) + { VkAttachmentReference reference{}; reference.attachment = attachment++; reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; @@ -1666,11 +1714,10 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) { VkAttachmentDescription colorDescription{}; colorDescription.format = colorFormat; colorDescription.samples = configuration.staticData.msaaSamples; - if (configuration.staticData.initialColorImageLayout != VK_IMAGE_LAYOUT_UNDEFINED) { + if (configuration.staticData.initialColorImageLayout != VK_IMAGE_LAYOUT_UNDEFINED) colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - } else { + else colorDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } colorDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE; colorDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; @@ -1683,7 +1730,8 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) { subPass.pColorAttachments = colorAttachmentRefs.data(); VkAttachmentReference depthStencilAttachmentRef{}; - if (configuration.staticData.depthFormat != VK_FORMAT_UNDEFINED) { + if (configuration.staticData.depthFormat != VK_FORMAT_UNDEFINED) + { depthStencilAttachmentRef.attachment = attachment++; depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; subPass.pDepthStencilAttachment = &depthStencilAttachmentRef; @@ -1701,7 +1749,8 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) { } VkAttachmentReference colorAttachmentResolveRef{}; - if (configuration.staticData.resolve) { + if (configuration.staticData.resolve) + { colorAttachmentResolveRef.attachment = attachment++; colorAttachmentResolveRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; subPass.pResolveAttachments = &colorAttachmentResolveRef; @@ -1746,21 +1795,22 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration configuration) { createInfo.pDependencies = dependencies.data(); VkRenderPass renderPass; - if (vkCreateRenderPass(device, &createInfo, nullptr, &renderPass) != VK_SUCCESS) { + if (vkCreateRenderPass(device, &createInfo, nullptr, &renderPass) != VK_SUCCESS) throw love::Exception("failed to create render pass"); - } return renderPass; } -bool Graphics::usesConstantVertexColor(const VertexAttributes& vertexAttributes) { +bool Graphics::usesConstantVertexColor(const VertexAttributes &vertexAttributes) +{ return !!(vertexAttributes.enableBits & (1u << ATTRIB_COLOR)); } void Graphics::createVulkanVertexFormat( VertexAttributes vertexAttributes, std::vector &bindingDescriptions, - std::vector &attributeDescriptions) { + std::vector &attributeDescriptions) +{ std::set usedBuffers; auto allBits = vertexAttributes.enableBits; @@ -1769,26 +1819,27 @@ void Graphics::createVulkanVertexFormat( uint8_t highestBufferBinding = 0; - for (uint32_t i = 0; i < VertexAttributes::MAX; i++) { // change to loop like in opengl implementation ? + // change to loop like in opengl implementation ? + for (uint32_t i = 0; i < VertexAttributes::MAX; i++) + { uint32 bit = 1u << i; - if (allBits & bit) { - if (i == ATTRIB_COLOR) { + if (allBits & bit) + { + if (i == ATTRIB_COLOR) usesColor = true; - } auto attrib = vertexAttributes.attribs[i]; auto bufferBinding = attrib.bufferIndex; - if (usedBuffers.find(bufferBinding) == usedBuffers.end()) { // use .contains() when c++20 is enabled + if (usedBuffers.find(bufferBinding) == usedBuffers.end()) // use .contains() when c++20 is enabled + { usedBuffers.insert(bufferBinding); VkVertexInputBindingDescription bindingDescription{}; bindingDescription.binding = bufferBinding; - if (vertexAttributes.instanceBits & (1u << bufferBinding)) { + if (vertexAttributes.instanceBits & (1u << bufferBinding)) bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; - } - else { + else bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - } bindingDescription.stride = vertexAttributes.bufferLayouts[bufferBinding].stride; bindingDescriptions.push_back(bindingDescription); @@ -1806,7 +1857,8 @@ void Graphics::createVulkanVertexFormat( } // do we need to use a constant VertexColor? - if (!usesColor) { + if (!usesColor) + { // FIXME: is there a case where gaps happen between buffer bindings? // then this doesn't work. We might need to enable null buffers again. const auto constantColorBufferBinding = highestBufferBinding + 1; @@ -1826,7 +1878,8 @@ void Graphics::createVulkanVertexFormat( } } -void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture, PrimitiveType primitiveType, CullMode cullmode) { +void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindings &buffers, graphics::Texture *texture, PrimitiveType primitiveType, CullMode cullmode) +{ GraphicsPipelineConfiguration configuration{}; configuration.renderPass = currentRenderPass; @@ -1839,9 +1892,10 @@ void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindi configuration.numColorAttachments = currentNumColorAttachments; configuration.primitiveType = primitiveType; - if (optionalDeviceFeatures.extendedDynamicState) { + if (optionalDeviceFeatures.extendedDynamicState) ext.vkCmdSetCullModeEXT(commandBuffers.at(currentFrame), Vulkan::getCullMode(cullmode)); - } else { + else + { configuration.dynamicState.winding = states.back().winding; configuration.dynamicState.depthState.compare = states.back().depthTest; configuration.dynamicState.depthState.write = states.back().depthWrite; @@ -1853,26 +1907,25 @@ void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindi std::vector bufferVector; std::vector offsets; - for (uint32_t i = 0; i < VertexAttributes::MAX; i++) { - if (buffers.useBits & (1u << i)) { + for (uint32_t i = 0; i < VertexAttributes::MAX; i++) + if (buffers.useBits & (1u << i)) + { bufferVector.push_back((VkBuffer)buffers.info[i].buffer->getHandle()); offsets.push_back((VkDeviceSize)buffers.info[i].offset); } - } - if (usesConstantVertexColor(attributes)) { + if (usesConstantVertexColor(attributes)) + { bufferVector.push_back((VkBuffer)batchedDrawBuffers[currentFrame].constantColorBuffer->getHandle()); offsets.push_back((VkDeviceSize)0); } auto currentUniformData = getCurrentBuiltinUniformData(); configuration.shader->setUniformData(currentUniformData); - if (texture == nullptr) { + if (texture == nullptr) configuration.shader->setMainTex(standardTexture.get()); - } - else { + else configuration.shader->setMainTex(texture); - } ensureGraphicsPipelineConfiguration(configuration); @@ -1880,7 +1933,8 @@ void Graphics::prepareDraw(const VertexAttributes& attributes, const BufferBindi vkCmdBindVertexBuffers(commandBuffers.at(currentFrame), 0, static_cast(bufferVector.size()), bufferVector.data(), offsets.data()); } -void Graphics::startDefaultRenderPass() { +void Graphics::startDefaultRenderPass() +{ VkRenderPassBeginInfo renderPassInfo{}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassInfo.renderPass = defaultRenderPass; @@ -1909,7 +1963,8 @@ void Graphics::startDefaultRenderPass() { vkCmdSetViewport(commandBuffers.at(currentFrame), 0, 1, &viewport); } -void Graphics::startRenderPass(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) { +void Graphics::startRenderPass(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture) +{ VkViewport viewport{}; viewport.x = 0.0f; viewport.y = 0.0f; @@ -1926,26 +1981,28 @@ void Graphics::startRenderPass(const RenderTargets& rts, int pixelw, int pixelh, // fixme: msaaSamples RenderPassConfiguration renderPassConfiguration{}; renderPassConfiguration.staticData.initialColorImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - for (const auto &color : rts.colors) { + for (const auto &color : rts.colors) + { // fixme: use mipmap and slice. color.mipmap; color.slice; renderPassConfiguration.colorFormats.push_back(Vulkan::getTextureFormat(color.texture->getPixelFormat()).internalFormat); } - if (rts.depthStencil.texture != nullptr) { + if (rts.depthStencil.texture != nullptr) + { // fixme: use mipmap and slice: rts.depthStencil.mipmap; rts.depthStencil.slice; - if (rts.depthStencil.texture != nullptr) { + if (rts.depthStencil.texture != nullptr) renderPassConfiguration.staticData.depthFormat = Vulkan::getTextureFormat(rts.depthStencil.texture->getPixelFormat()).internalFormat; - } } VkRenderPass renderPass; auto it = renderPasses.find(renderPassConfiguration); - if (it != renderPasses.end()) { + if (it != renderPasses.end()) renderPass = it->second; - } else { + else + { renderPass = createRenderPass(renderPassConfiguration); renderPasses[renderPassConfiguration] = renderPass; } @@ -1954,15 +2011,15 @@ void Graphics::startRenderPass(const RenderTargets& rts, int pixelw, int pixelh, std::vector transitionBackImages; - for (const auto& color : rts.colors) { + for (const auto& color : rts.colors) + { configuration.colorViews.push_back((VkImageView)color.texture->getRenderTargetHandle()); Vulkan::cmdTransitionImageLayout(currentCommandBuffer, (VkImage)color.texture->getHandle(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); transitionBackImages.push_back((VkImage) color.texture->getHandle()); } - if (rts.depthStencil.texture != nullptr) { - configuration.staticData.depthView = (VkImageView)rts.depthStencil.texture->getRenderTargetHandle(); + if (rts.depthStencil.texture != nullptr) // fixme: layout transition of depth stencil image? - } + configuration.staticData.depthView = (VkImageView)rts.depthStencil.texture->getRenderTargetHandle(); configuration.staticData.renderPass = renderPass; configuration.staticData.width = static_cast(pixelw); @@ -1987,23 +2044,25 @@ void Graphics::startRenderPass(const RenderTargets& rts, int pixelw, int pixelh, currentNumColorAttachments = static_cast(rts.colors.size()); postRenderPass = [=]() { - for (const auto& image : transitionBackImages) { + for (const auto& image : transitionBackImages) Vulkan::cmdTransitionImageLayout(currentCommandBuffer, image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - } }; } -void Graphics::endRenderPass() { +void Graphics::endRenderPass() +{ vkCmdEndRenderPass(commandBuffers.at(currentFrame)); currentRenderPass = VK_NULL_HANDLE; - if (postRenderPass) { + if (postRenderPass) + { postRenderPass.value()(); postRenderPass = std::nullopt; } } -VkSampler Graphics::createSampler(const SamplerState& samplerState) { +VkSampler Graphics::createSampler(const SamplerState &samplerState) +{ VkPhysicalDeviceProperties properties{}; vkGetPhysicalDeviceProperties(physicalDevice, &properties); @@ -2018,10 +2077,13 @@ VkSampler Graphics::createSampler(const SamplerState& samplerState) { samplerInfo.maxAnisotropy = static_cast(samplerState.maxAnisotropy); samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; samplerInfo.unnormalizedCoordinates = VK_FALSE; - if (samplerState.depthSampleMode.hasValue) { + if (samplerState.depthSampleMode.hasValue) + { samplerInfo.compareEnable = VK_TRUE; samplerInfo.compareOp = Vulkan::getCompareOp(samplerState.depthSampleMode.value); - } else { + } + else + { samplerInfo.compareEnable = VK_FALSE; samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; } @@ -2031,37 +2093,42 @@ VkSampler Graphics::createSampler(const SamplerState& samplerState) { samplerInfo.maxLod = static_cast(samplerState.maxLod); VkSampler sampler; - if (vkCreateSampler(device, &samplerInfo, nullptr, &sampler) != VK_SUCCESS) { + if (vkCreateSampler(device, &samplerInfo, nullptr, &sampler) != VK_SUCCESS) throw love::Exception("failed to create sampler"); - } return sampler; } -void Graphics::setComputeShader(Shader* shader) { +void Graphics::setComputeShader(Shader *shader) +{ computeShader = shader; } -const OptionalDeviceFeatures &Graphics::getOptionalDeviceFeatures() const { +const OptionalDeviceFeatures &Graphics::getOptionalDeviceFeatures() const +{ return optionalDeviceFeatures; } -const OptionalDeviceExtensionFunctions &Graphics::getExtensionFunctions() const { +const OptionalDeviceExtensionFunctions &Graphics::getExtensionFunctions() const +{ return ext; } -VkSampler Graphics::getCachedSampler(const SamplerState& samplerState) { +VkSampler Graphics::getCachedSampler(const SamplerState &samplerState) +{ auto it = samplers.find(samplerState); - if (it != samplers.end()) { + if (it != samplers.end()) return it->second; - } else { + else + { VkSampler sampler = createSampler(samplerState); samplers.insert({samplerState, sampler}); return sampler; } } -VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration configuration) { +VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &configuration) +{ VkGraphicsPipelineCreateInfo pipelineInfo{}; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; @@ -2099,7 +2166,8 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config rasterizer.rasterizerDiscardEnable = VK_FALSE; rasterizer.polygonMode = Vulkan::getPolygonMode(configuration.wireFrame); rasterizer.lineWidth = 1.0f; - if (!optionalDeviceFeatures.extendedDynamicState) { + if (!optionalDeviceFeatures.extendedDynamicState) + { rasterizer.cullMode = Vulkan::getCullMode(configuration.dynamicState.cullmode); rasterizer.frontFace = Vulkan::getFrontFace(configuration.dynamicState.winding); } @@ -2117,7 +2185,8 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config VkPipelineDepthStencilStateCreateInfo depthStencil{}; depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; depthStencil.depthTestEnable = VK_TRUE; - if (!optionalDeviceFeatures.extendedDynamicState) { + if (!optionalDeviceFeatures.extendedDynamicState) + { depthStencil.depthWriteEnable = Vulkan::getBool(configuration.dynamicState.depthState.write); depthStencil.depthCompareOp = Vulkan::getCompareOp(configuration.dynamicState.depthState.compare); } @@ -2127,7 +2196,8 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config depthStencil.stencilTestEnable = VK_TRUE; - if (!optionalDeviceFeatures.extendedDynamicState) { + if (!optionalDeviceFeatures.extendedDynamicState) + { depthStencil.front.failOp = VK_STENCIL_OP_KEEP; depthStencil.front.passOp = Vulkan::getStencilOp(configuration.dynamicState.stencilAction); depthStencil.front.depthFailOp = VK_STENCIL_OP_KEEP; @@ -2166,7 +2236,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config std::vector dynamicStates; - if (optionalDeviceFeatures.extendedDynamicState) { + if (optionalDeviceFeatures.extendedDynamicState) dynamicStates = { VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_VIEWPORT, @@ -2179,15 +2249,13 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT, VK_DYNAMIC_STATE_STENCIL_OP_EXT, }; - } - else { + else dynamicStates = { VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE, }; - } VkPipelineDynamicStateCreateInfo dynamicState{}; dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; @@ -2210,20 +2278,23 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration config pipelineInfo.renderPass = configuration.renderPass; VkPipeline graphicsPipeline; - if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) { + if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) throw love::Exception("failed to create graphics pipeline"); - } return graphicsPipeline; } -void Graphics::ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration configuration) { +void Graphics::ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration &configuration) { auto it = graphicsPipelines.find(configuration); - if (it != graphicsPipelines.end()) { - if (it->second != currentGraphicsPipeline) { + if (it != graphicsPipelines.end()) + { + if (it->second != currentGraphicsPipeline) + { vkCmdBindPipeline(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS, it->second); currentGraphicsPipeline = it->second; } - } else { + } + else + { VkPipeline pipeline = createGraphicsPipeline(configuration); graphicsPipelines.insert({configuration, pipeline}); vkCmdBindPipeline(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); @@ -2231,7 +2302,8 @@ void Graphics::ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration } } -void Graphics::getMaxUsableSampleCount() { +void Graphics::getMaxUsableSampleCount() +{ VkPhysicalDeviceProperties physicalDeviceProperties; vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties); @@ -2253,12 +2325,15 @@ void Graphics::getMaxUsableSampleCount() { msaaSamples = VK_SAMPLE_COUNT_1_BIT; } -void Graphics::createColorResources() { - if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) { +void Graphics::createColorResources() +{ + if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) + { colorImage = VK_NULL_HANDLE; colorImageView = VK_NULL_HANDLE; } - else { + else + { VkFormat colorFormat = swapChainImageFormat; VkImageCreateInfo imageInfo{}; @@ -2301,22 +2376,23 @@ void Graphics::createColorResources() { } } -VkFormat Graphics::findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features) { - for (auto format : candidates) { +VkFormat Graphics::findSupportedFormat(const std::vector &candidates, VkImageTiling tiling, VkFormatFeatureFlags features) +{ + for (auto format : candidates) + { VkFormatProperties properties; vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &properties); - if (tiling == VK_IMAGE_TILING_LINEAR && (properties.linearTilingFeatures & features) == features) { + if (tiling == VK_IMAGE_TILING_LINEAR && (properties.linearTilingFeatures & features) == features) return format; - } - else if (tiling == VK_IMAGE_TILING_OPTIMAL && (properties.optimalTilingFeatures & features) == features) { + else if (tiling == VK_IMAGE_TILING_OPTIMAL && (properties.optimalTilingFeatures & features) == features) return format; - } } throw love::Exception("failed to find supported format"); } -VkFormat Graphics::findDepthFormat() { +VkFormat Graphics::findDepthFormat() +{ return findSupportedFormat( { VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT }, VK_IMAGE_TILING_OPTIMAL, @@ -2324,7 +2400,8 @@ VkFormat Graphics::findDepthFormat() { ); } -void Graphics::createDepthResources() { +void Graphics::createDepthResources() +{ VkFormat depthFormat = findDepthFormat(); VkImageCreateInfo imageInfo{}; @@ -2366,7 +2443,8 @@ void Graphics::createDepthResources() { vkCreateImageView(device, &imageViewInfo, nullptr, &depthImageView); } -void Graphics::createCommandPool() { +void Graphics::createCommandPool() +{ QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice); VkCommandPoolCreateInfo poolInfo{}; @@ -2374,12 +2452,12 @@ void Graphics::createCommandPool() { poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value(); poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; - if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) { + if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) throw love::Exception("failed to create command pool"); - } } -void Graphics::createCommandBuffers() { +void Graphics::createCommandBuffers() +{ commandBuffers.resize(MAX_FRAMES_IN_FLIGHT); dataTransferCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT); readbackCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT); @@ -2391,9 +2469,8 @@ void Graphics::createCommandBuffers() { allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.commandBufferCount = static_cast(MAX_FRAMES_IN_FLIGHT); - if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) { + if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) throw love::Exception("failed to allocate command buffers"); - } VkCommandBufferAllocateInfo dataTransferAllocInfo{}; dataTransferAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; @@ -2401,9 +2478,8 @@ void Graphics::createCommandBuffers() { dataTransferAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; dataTransferAllocInfo.commandBufferCount = static_cast(MAX_FRAMES_IN_FLIGHT); - if (vkAllocateCommandBuffers(device, &dataTransferAllocInfo, dataTransferCommandBuffers.data()) != VK_SUCCESS) { + if (vkAllocateCommandBuffers(device, &dataTransferAllocInfo, dataTransferCommandBuffers.data()) != VK_SUCCESS) throw love::Exception("failed to allocate data transfer command buffers"); - } VkCommandBufferAllocateInfo readbackAllocInfo{}; readbackAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; @@ -2411,9 +2487,8 @@ void Graphics::createCommandBuffers() { readbackAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; readbackAllocInfo.commandBufferCount = static_cast(MAX_FRAMES_IN_FLIGHT); - if (vkAllocateCommandBuffers(device, &readbackAllocInfo, readbackCommandBuffers.data()) != VK_SUCCESS) { + if (vkAllocateCommandBuffers(device, &readbackAllocInfo, readbackCommandBuffers.data()) != VK_SUCCESS) throw love::Exception("failed to allocate readback command buffers"); - } VkCommandBufferAllocateInfo commandAllocInfo{}; commandAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; @@ -2421,12 +2496,12 @@ void Graphics::createCommandBuffers() { commandAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; commandAllocInfo.commandBufferCount = static_cast(MAX_FRAMES_IN_FLIGHT); - if (vkAllocateCommandBuffers(device, &commandAllocInfo, computeCommandBuffers.data()) != VK_SUCCESS) { + if (vkAllocateCommandBuffers(device, &commandAllocInfo, computeCommandBuffers.data()) != VK_SUCCESS) throw love::Exception("failed to allocate compute command buffers"); - } } -void Graphics::createSyncObjects() { +void Graphics::createSyncObjects() +{ imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT); renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT); inFlightFences.resize(MAX_FRAMES_IN_FLIGHT); @@ -2439,35 +2514,34 @@ void Graphics::createSyncObjects() { fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores.at(i)) != VK_SUCCESS || vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores.at(i)) != VK_SUCCESS || - vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences.at(i)) != VK_SUCCESS) { + vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences.at(i)) != VK_SUCCESS) throw love::Exception("failed to create synchronization objects for a frame!"); - } - } } -void Graphics::createDefaultTexture() { +void Graphics::createDefaultTexture() +{ Texture::Settings settings; standardTexture.reset((Texture*)newTexture(settings, nullptr)); uint8_t whitePixels[] = {255, 255, 255, 255}; standardTexture->replacePixels(whitePixels, sizeof(whitePixels), 0, 0, { 0, 0, 1, 1 }, false); } -void Graphics::cleanup() { +void Graphics::cleanup() +{ cleanupSwapChain(); - for (auto &cleanUpFns : cleanUpFunctions) { - for (auto &cleanUpFn : cleanUpFns) { + for (auto &cleanUpFns : cleanUpFunctions) + for (auto &cleanUpFn : cleanUpFns) cleanUpFn(); - } - } cleanUpFunctions.clear(); vmaDestroyAllocator(vmaAllocator); batchedDrawBuffers.clear(); - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) + { vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr); vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr); vkDestroyFence(device, inFlightFences[i], nullptr); @@ -2478,19 +2552,16 @@ void Graphics::cleanup() { vkFreeCommandBuffers(device, commandPool, MAX_FRAMES_IN_FLIGHT, readbackCommandBuffers.data()); vkFreeCommandBuffers(device, commandPool, MAX_FRAMES_IN_FLIGHT, computeCommandBuffers.data()); - for (auto const& p : samplers) { + for (auto const &p : samplers) vkDestroySampler(device, p.second, nullptr); - } samplers.clear(); - for (const auto& [key, val] : renderPasses) { + for (const auto &[key, val] : renderPasses) vkDestroyRenderPass(device, val, nullptr); - } // fixme: maybe we should clean up some pipelines if they haven't been used in a while. - for (auto const& p : graphicsPipelines) { + for (auto const &p : graphicsPipelines) vkDestroyPipeline(device, p.second, nullptr); - } graphicsPipelines.clear(); vkDestroyCommandPool(device, commandPool, nullptr); @@ -2499,27 +2570,26 @@ void Graphics::cleanup() { vkDestroyInstance(instance, nullptr); } -void Graphics::cleanupSwapChain() { - for (const auto& framebuffer : defaultFramebuffers) { +void Graphics::cleanupSwapChain() +{ + for (const auto &framebuffer : defaultFramebuffers) vkDestroyFramebuffer(device, framebuffer, nullptr); - } vkDestroyRenderPass(device, defaultRenderPass, nullptr); vkDestroyImageView(device, colorImageView, nullptr); vmaDestroyImage(vmaAllocator, colorImage, colorImageAllocation); vkDestroyImageView(device, depthImageView, nullptr); vmaDestroyImage(vmaAllocator, depthImage, depthImageAllocation); - for (const auto& [key, val] : framebuffers) { + for (const auto &[key, val] : framebuffers) vkDestroyFramebuffer(device, val, nullptr); - } framebuffers.clear(); - for (auto & swapChainImageView : swapChainImageViews) { + for (const auto &swapChainImageView : swapChainImageViews) vkDestroyImageView(device, swapChainImageView, nullptr); - } swapChainImageViews.clear(); vkDestroySwapchainKHR(device, swapChain, nullptr); } -void Graphics::recreateSwapChain() { +void Graphics::recreateSwapChain() +{ vkDeviceWaitIdle(device); cleanupSwapChain(); @@ -2532,18 +2602,22 @@ void Graphics::recreateSwapChain() { createDefaultFramebuffers(); } -love::graphics::Graphics* createInstance() { - love::graphics::Graphics* instance = nullptr; +love::graphics::Graphics *createInstance() +{ + love::graphics::Graphics *instance = nullptr; - try { + try + { instance = new Graphics(); } - catch (love::Exception& e) { + catch (love::Exception &e) + { printf("Cannot create Vulkan renderer: %s\n", e.what()); } return instance; } + } // vulkan } // graphics } // love diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index f498361a1..0891412d8 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -1,5 +1,4 @@ -#ifndef LOVE_GRAPHICS_VULKAN_GRAPHICS_H -#define LOVE_GRAPHICS_VULKAN_GRAPHICS_H +#pragma once // löve #include "common/config.h" @@ -20,27 +19,36 @@ #include -namespace love { -namespace graphics { -namespace vulkan { -struct RenderPassConfiguration { +namespace love +{ +namespace graphics +{ +namespace vulkan +{ + +struct RenderPassConfiguration +{ std::vector colorFormats; - struct StaticRenderPassConfiguration { + struct StaticRenderPassConfiguration + { VkImageLayout initialColorImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT; VkFormat depthFormat = VK_FORMAT_UNDEFINED; bool resolve = false; } staticData; - bool operator==(const RenderPassConfiguration& conf) const { + bool operator==(const RenderPassConfiguration &conf) const + { return colorFormats == conf.colorFormats && (memcmp(&staticData, &conf.staticData, sizeof(StaticRenderPassConfiguration)) == 0); } }; -struct RenderPassConfigurationHasher { - size_t operator()(const RenderPassConfiguration &configuration) const { +struct RenderPassConfigurationHasher +{ + size_t operator()(const RenderPassConfiguration &configuration) const + { size_t hashes[] = { XXH32(configuration.colorFormats.data(), configuration.colorFormats.size() * sizeof(VkFormat), 0), XXH32(&configuration.staticData, sizeof(configuration.staticData), 0), @@ -49,10 +57,12 @@ struct RenderPassConfigurationHasher { } }; -struct FramebufferConfiguration { +struct FramebufferConfiguration +{ std::vector colorViews; - struct StaticFramebufferConfiguration { + struct StaticFramebufferConfiguration + { VkImageView depthView = VK_NULL_HANDLE; VkImageView resolveView = VK_NULL_HANDLE; @@ -62,14 +72,17 @@ struct FramebufferConfiguration { VkRenderPass renderPass = VK_NULL_HANDLE; } staticData; - bool operator==(const FramebufferConfiguration& conf) const { + bool operator==(const FramebufferConfiguration &conf) const + { return colorViews == conf.colorViews && (memcmp(&staticData, &conf.staticData, sizeof(StaticFramebufferConfiguration)) == 0); } }; -struct FramebufferConfigurationHasher { - size_t operator()(const FramebufferConfiguration& configuration) const { +struct FramebufferConfigurationHasher +{ + size_t operator()(const FramebufferConfiguration &configuration) const + { size_t hashes[] = { XXH32(configuration.colorViews.data(), configuration.colorViews.size() * sizeof(VkImageView), 0), XXH32(&configuration.staticData, sizeof(configuration.staticData), 0), @@ -79,16 +92,19 @@ struct FramebufferConfigurationHasher { } }; -struct OptionalInstanceExtensions { +struct OptionalInstanceExtensions +{ bool physicalDeviceProperties2 = false; }; -struct OptionalDeviceFeatures { +struct OptionalDeviceFeatures +{ bool extendedDynamicState = false; bool pushDescriptor = false; }; -struct OptionalDeviceExtensionFunctions { +struct OptionalDeviceExtensionFunctions +{ // extended dynamic state PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT = nullptr; PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT = nullptr; @@ -106,7 +122,8 @@ struct OptionalDeviceExtensionFunctions { PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR = nullptr; }; -struct GraphicsPipelineConfiguration { +struct GraphicsPipelineConfiguration +{ VkRenderPass renderPass; VertexAttributes vertexAttributes; Shader* shader = nullptr; @@ -117,7 +134,8 @@ struct GraphicsPipelineConfiguration { uint32_t numColorAttachments; PrimitiveType primitiveType; - struct DynamicState { + struct DynamicState + { CullMode cullmode = CULL_NONE; Winding winding = WINDING_MAX_ENUM; StencilAction stencilAction = STENCIL_MAX_ENUM; @@ -125,34 +143,42 @@ struct GraphicsPipelineConfiguration { DepthState depthState{}; } dynamicState; - GraphicsPipelineConfiguration() { + GraphicsPipelineConfiguration() + { memset(this, 0, sizeof(GraphicsPipelineConfiguration)); } - bool operator==(const GraphicsPipelineConfiguration& other) const { + bool operator==(const GraphicsPipelineConfiguration &other) const + { return memcmp(this, &other, sizeof(GraphicsPipelineConfiguration)) == 0; } }; -struct GraphicsPipelineConfigurationHasher { - size_t operator() (const GraphicsPipelineConfiguration &configuration) const { +struct GraphicsPipelineConfigurationHasher +{ + size_t operator() (const GraphicsPipelineConfiguration &configuration) const + { return XXH32(&configuration, sizeof(GraphicsPipelineConfiguration), 0); } }; -struct SamplerStateHasher { - size_t operator()(const SamplerState &samplerState) const { +struct SamplerStateHasher +{ + size_t operator()(const SamplerState &samplerState) const + { return XXH32(&samplerState, sizeof(SamplerState), 0); } }; -struct BatchedDrawBuffers { +struct BatchedDrawBuffers +{ StreamBuffer* vertexBuffer1; StreamBuffer* vertexBuffer2; StreamBuffer* indexBuffer; StreamBuffer* constantColorBuffer; - ~BatchedDrawBuffers() { + ~BatchedDrawBuffers() + { delete vertexBuffer1; delete vertexBuffer2; delete indexBuffer; @@ -160,22 +186,26 @@ struct BatchedDrawBuffers { } }; -struct QueueFamilyIndices { +struct QueueFamilyIndices +{ std::optional graphicsFamily; std::optional presentFamily; - bool isComplete() const { + bool isComplete() const + { return graphicsFamily.has_value() && presentFamily.has_value(); } }; -struct SwapChainSupportDetails { +struct SwapChainSupportDetails +{ VkSurfaceCapabilitiesKHR capabilities{}; std::vector formats; std::vector presentModes; }; -class Graphics final : public love::graphics::Graphics { +class Graphics final : public love::graphics::Graphics +{ public: #ifdef LOVE_ANDROID Graphics() { @@ -196,27 +226,27 @@ public: const VmaAllocator getVmaAllocator() const; // implementation for virtual functions - love::graphics::Texture* newTexture(const love::graphics::Texture::Settings& settings, const love::graphics::Texture::Slices* data) override; - love::graphics::Buffer* newBuffer(const love::graphics::Buffer::Settings& settings, const std::vector& format, const void* data, size_t size, size_t arraylength) override; + love::graphics::Texture *newTexture(const love::graphics::Texture::Settings &settings, const love::graphics::Texture::Slices *data) override; + love::graphics::Buffer *newBuffer(const love::graphics::Buffer::Settings &settings, const std::vector& format, const void *data, size_t size, size_t arraylength) override; void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override; - void clear(const std::vector& colors, OptionalInt stencil, OptionalDouble depth) override; - Matrix4 computeDeviceProjection(const Matrix4& projection, bool rendertotexture) const override; - void discard(const std::vector& colorbuffers, bool depthstencil) override { } - void present(void* screenshotCallbackdata) override; + void clear(const std::vector &colors, OptionalInt stencil, OptionalDouble depth) override; + Matrix4 computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const override; + void discard(const std::vector &colorbuffers, bool depthstencil) override { } + void present(void *screenshotCallbackdata) override; void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override; - bool setMode(void* context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override; + bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override; void unSetMode() override; void setActive(bool active) override; int getRequestedBackbufferMSAA() const override; int getBackbufferMSAA() const override; void setColor(Colorf c) override; - void setScissor(const Rect& rect) override; + void setScissor(const Rect &rect) override; void setScissor() override; void setStencilMode(StencilAction action, CompareMode compare, int value, love::uint32 readmask, love::uint32 writemask) override; void setDepthMode(CompareMode compare, bool write) override; void setFrontFaceWinding(Winding winding) override; void setColorMask(ColorChannelMask mask) override; - void setBlendState(const BlendState& blend) override; + void setBlendState(const BlendState &blend) override; void setPointSize(float size) override; void setWireframe(bool enable) override; PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override; @@ -224,12 +254,12 @@ public: Renderer getRenderer() const override; bool usesGLSLES() const override; RendererInfo getRendererInfo() const override; - void draw(const DrawCommand& cmd) override; - void draw(const DrawIndexedCommand& cmd) override; - void drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture) override; + void draw(const DrawCommand &cmd) override; + void draw(const DrawIndexedCommand &cmd) override; + void drawQuads(int start, int count, const VertexAttributes &attributes, const BufferBindings &buffers, graphics::Texture *texture) override; - graphics::GraphicsReadback* newReadbackInternal(ReadbackMethod method, love::graphics::Buffer* buffer, size_t offset, size_t size, data::ByteData* dest, size_t destoffset) override; - graphics::GraphicsReadback* newReadbackInternal(ReadbackMethod method, love::graphics::Texture* texture, int slice, int mipmap, const Rect& rect, image::ImageData* dest, int destx, int desty) override; + graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset) override; + graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Texture *texture, int slice, int mipmap, const Rect &rect, image::ImageData *dest, int destx, int desty) override; VkCommandBuffer getDataTransferCommandBuffer(); VkCommandBuffer getReadbackCommandBuffer(); @@ -243,7 +273,7 @@ public: uint32_t getNumImagesInFlight() const; const VkDeviceSize getMinUniformBufferOffsetAlignment() const; - graphics::Texture* getDefaultTexture() const; + graphics::Texture *getDefaultTexture() const; VkSampler getCachedSampler(const SamplerState&); void setComputeShader(Shader*); @@ -252,13 +282,13 @@ public: const OptionalDeviceExtensionFunctions &getExtensionFunctions() const; protected: - graphics::ShaderStage* newShaderStageInternal(ShaderStageType stage, const std::string& cachekey, const std::string& source, bool gles) override; - graphics::Shader* newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) override; - graphics::StreamBuffer* newStreamBuffer(BufferUsage type, size_t size) override; + graphics::ShaderStage *newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles) override; + graphics::Shader *newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) override; + graphics::StreamBuffer *newStreamBuffer(BufferUsage type, size_t size) override; bool dispatch(int x, int y, int z) override; void initCapabilities() override; - void getAPIStats(int& shaderswitches) const override; - void setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) override; + void getAPIStats(int &shaderswitches) const override; + void setRenderTargetsInternal(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture) override; private: void createVulkanInstance(); @@ -272,21 +302,21 @@ private: void createSurface(); bool checkDeviceExtensionSupport(VkPhysicalDevice device); SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device); - VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector& availableFormats); - VkPresentModeKHR chooseSwapPresentMode(const std::vector& availablePresentModes); - VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities); - VkCompositeAlphaFlagBitsKHR chooseCompositeAlpha(const VkSurfaceCapabilitiesKHR& capabilities); + VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector &availableFormats); + VkPresentModeKHR chooseSwapPresentMode(const std::vector &availablePresentModes); + VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR &capabilities); + VkCompositeAlphaFlagBitsKHR chooseCompositeAlpha(const VkSurfaceCapabilitiesKHR &capabilities); void createSwapChain(); void createImageViews(); void createDefaultRenderPass(); void createDefaultFramebuffers(); - VkFramebuffer createFramebuffer(FramebufferConfiguration); - VkFramebuffer getFramebuffer(FramebufferConfiguration); + VkFramebuffer createFramebuffer(FramebufferConfiguration&); + VkFramebuffer getFramebuffer(FramebufferConfiguration&); void createDefaultShaders(); - VkRenderPass createRenderPass(RenderPassConfiguration); - VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration); + VkRenderPass createRenderPass(RenderPassConfiguration&); + VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration&); void createColorResources(); - VkFormat findSupportedFormat(const std::vector& candidates, VkImageTiling tiling, VkFormatFeatureFlags features); + VkFormat findSupportedFormat(const std::vector &candidates, VkImageTiling tiling, VkFormatFeatureFlags features); VkFormat findDepthFormat(); void createDepthResources(); void createCommandPool(); @@ -300,7 +330,7 @@ private: void beginFrame(); void startRecordingGraphicsCommands(bool newFrame); void endRecordingGraphicsCommands(bool present); - void ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration); + void ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration&); graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData(); void updatedBatchedDrawBuffers(); bool usesConstantVertexColor(const VertexAttributes&); @@ -308,8 +338,8 @@ private: VertexAttributes vertexAttributes, std::vector &bindingDescriptions, std::vector &attributeDescriptions); - void prepareDraw(const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture, PrimitiveType, CullMode); - void startRenderPass(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture); + void prepareDraw(const VertexAttributes &attributes, const BufferBindings &buffers, graphics::Texture *texture, PrimitiveType, CullMode); + void startRenderPass(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture); void startDefaultRenderPass(); void endRenderPass(); VkSampler createSampler(const SamplerState&); @@ -378,8 +408,7 @@ private: float currentViewportHeight = 0; VkSampleCountFlagBits currentMsaaSamples = VK_SAMPLE_COUNT_1_BIT; }; + } // vulkan } // graphics } // love - -#endif diff --git a/src/modules/graphics/vulkan/GraphicsReadback.cpp b/src/modules/graphics/vulkan/GraphicsReadback.cpp index 7c7489bd9..30b567cb8 100644 --- a/src/modules/graphics/vulkan/GraphicsReadback.cpp +++ b/src/modules/graphics/vulkan/GraphicsReadback.cpp @@ -4,21 +4,26 @@ #include "Graphics.h" #include "data/ByteData.h" -namespace love { -namespace graphics { -namespace vulkan { - -GraphicsReadback::GraphicsReadback(love::graphics::Graphics* gfx, ReadbackMethod method, love::graphics::Buffer* buffer, size_t offset, size_t size, data::ByteData* dest, size_t destoffset) - : graphics::GraphicsReadback(gfx, method, buffer, offset, size, dest, destoffset) { - vgfx = dynamic_cast(gfx); +namespace love +{ +namespace graphics +{ +namespace vulkan +{ +GraphicsReadback::GraphicsReadback(love::graphics::Graphics *gfx, ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset) + : graphics::GraphicsReadback(gfx, method, buffer, offset, size, dest, destoffset) + , vgfx(dynamic_cast(gfx)) +{ // Immediate readback of readback-type buffers doesn't need a staging buffer. - if (method != READBACK_IMMEDIATE || buffer->getDataUsage() != BUFFERDATAUSAGE_READBACK) { + if (method != READBACK_IMMEDIATE || buffer->getDataUsage() != BUFFERDATAUSAGE_READBACK) + { stagingBuffer = gfx->getTemporaryBuffer(size, DATAFORMAT_FLOAT, 0, BUFFERDATAUSAGE_READBACK); gfx->copyBuffer(buffer, stagingBuffer, offset, 0, size); } - if (method == READBACK_IMMEDIATE) { + if (method == READBACK_IMMEDIATE) + { vgfx->submitGpuCommands(false); if (stagingBuffer.get()) { status = readbackBuffer(stagingBuffer, 0, size); @@ -36,10 +41,10 @@ GraphicsReadback::GraphicsReadback(love::graphics::Graphics* gfx, ReadbackMethod }); } -GraphicsReadback::GraphicsReadback(love::graphics::Graphics* gfx, ReadbackMethod method, love::graphics::Texture* texture, int slice, int mipmap, const Rect& rect, image::ImageData* dest, int destx, int desty) - : graphics::GraphicsReadback(gfx, method, texture, slice, mipmap, rect, dest, destx, desty) { - vgfx = dynamic_cast(gfx); - +GraphicsReadback::GraphicsReadback(love::graphics::Graphics *gfx, ReadbackMethod method, love::graphics::Texture *texture, int slice, int mipmap, const Rect &rect, image::ImageData *dest, int destx, int desty) + : graphics::GraphicsReadback(gfx, method, texture, slice, mipmap, rect, dest, destx, desty) + , vgfx(dynamic_cast(gfx)) +{ size_t size = getPixelFormatSliceSize(textureFormat, rect.w, rect.h); stagingBuffer = vgfx->getTemporaryBuffer(size, DATAFORMAT_FLOAT, 0, BUFFERDATAUSAGE_READBACK); @@ -57,15 +62,18 @@ GraphicsReadback::GraphicsReadback(love::graphics::Graphics* gfx, ReadbackMethod vgfx->submitGpuCommands(false); } -GraphicsReadback::~GraphicsReadback() { +GraphicsReadback::~GraphicsReadback() +{ } -void GraphicsReadback::wait() { +void GraphicsReadback::wait() +{ if (status == STATUS_WAITING) vgfx->submitGpuCommands(false); } -void GraphicsReadback::update() { +void GraphicsReadback::update() +{ } } // vulkan diff --git a/src/modules/graphics/vulkan/GraphicsReadback.h b/src/modules/graphics/vulkan/GraphicsReadback.h index 3148b5f57..1d0355e7b 100644 --- a/src/modules/graphics/vulkan/GraphicsReadback.h +++ b/src/modules/graphics/vulkan/GraphicsReadback.h @@ -1,18 +1,21 @@ -#ifndef LOVE_GRAPHICS_VULKAN_GRAPHICS_READBACK_H -#define LOVE_GRAPHICS_VULKAN_GRAPHICS_READBACK_H +#pragma once #include "graphics/GraphicsReadback.h" -namespace love { -namespace graphics { -namespace vulkan { +namespace love +{ +namespace graphics +{ +namespace vulkan +{ class Graphics; -class GraphicsReadback : public graphics::GraphicsReadback { +class GraphicsReadback : public graphics::GraphicsReadback +{ public: - GraphicsReadback(love::graphics::Graphics* gfx, ReadbackMethod method, love::graphics::Buffer* buffer, size_t offset, size_t size, data::ByteData* dest, size_t destoffset); - GraphicsReadback(love::graphics::Graphics* gfx, ReadbackMethod method, love::graphics::Texture* texture, int slice, int mipmap, const Rect& rect, image::ImageData* dest, int destx, int desty); + GraphicsReadback(love::graphics::Graphics *gfx, ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset); + GraphicsReadback(love::graphics::Graphics *gfx, ReadbackMethod method, love::graphics::Texture *texture, int slice, int mipmap, const Rect &rect, image::ImageData *dest, int destx, int desty); virtual ~GraphicsReadback(); void wait() override; @@ -20,12 +23,10 @@ public: private: - Graphics* vgfx; + Graphics *vgfx = nullptr; StrongRef stagingBuffer; }; } // vulkan } // graphics } // love - -#endif diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 8dc4e20e0..fd34ebd63 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -7,9 +7,13 @@ #include -namespace love { -namespace graphics { -namespace vulkan { +namespace love +{ +namespace graphics +{ +namespace vulkan +{ + static const TBuiltInResource defaultTBuiltInResource = { /* .MaxLights = */ 32, /* .MaxClipPlanes = */ 6, @@ -120,8 +124,10 @@ static const TBuiltInResource defaultTBuiltInResource = { static const uint32_t STREAMBUFFER_DEFAULT_SIZE = 16; static const uint32_t DESCRIPTOR_POOL_SIZE = 1; -static VkShaderStageFlagBits getStageBit(ShaderStageType type) { - switch (type) { +static VkShaderStageFlagBits getStageBit(ShaderStageType type) +{ + switch (type) + { case SHADERSTAGE_VERTEX: return VK_SHADER_STAGE_VERTEX_BIT; case SHADERSTAGE_PIXEL: @@ -133,8 +139,10 @@ static VkShaderStageFlagBits getStageBit(ShaderStageType type) { } } -static EShLanguage getGlslShaderType(ShaderStageType stage) { - switch (stage) { +static EShLanguage getGlslShaderType(ShaderStageType stage) +{ + switch (stage) + { case SHADERSTAGE_VERTEX: return EShLangVertex; case SHADERSTAGE_PIXEL: @@ -147,30 +155,30 @@ static EShLanguage getGlslShaderType(ShaderStageType stage) { } Shader::Shader(StrongRef stages[]) - : graphics::Shader(stages) { - gfx = Module::getInstance(Module::ModuleType::M_GRAPHICS); - auto vgfx = (Graphics*)gfx; + : graphics::Shader(stages) +{ + auto gfx = Module::getInstance(Module::ModuleType::M_GRAPHICS); + vgfx = dynamic_cast(gfx); auto &optionalDeviceFeaures = vgfx->getOptionalDeviceFeatures(); - if (optionalDeviceFeaures.pushDescriptor) { + if (optionalDeviceFeaures.pushDescriptor) pfn_vkCmdPushDescriptorSetKHR = vgfx->getExtensionFunctions().vkCmdPushDescriptorSetKHR; - } loadVolatile(); } -bool Shader::loadVolatile() { +bool Shader::loadVolatile() +{ computePipeline = VK_NULL_HANDLE; - for (int i = 0; i < BUILTIN_MAX_ENUM; i++) { + for (int i = 0; i < BUILTIN_MAX_ENUM; i++) builtinUniformInfo[i] = nullptr; - } compileShaders(); calculateUniformBufferSizeAligned(); createDescriptorSetLayout(); createPipelineLayout(); createStreamBuffers(); - descriptorSetsVector.resize(((Graphics*)gfx)->getNumImagesInFlight()); + descriptorSetsVector.resize(vgfx->getNumImagesInFlight()); currentFrame = 0; currentUsedUniformStreamBuffersCount = 0; currentUsedDescriptorSetsCount = 0; @@ -178,19 +186,17 @@ bool Shader::loadVolatile() { return true; } -void Shader::unloadVolatile() { - if (shaderModules.empty()) { +void Shader::unloadVolatile() +{ + if (shaderModules.empty()) return; - } auto gfx = Module::getInstance(Module::M_GRAPHICS); gfx->queueCleanUp([shaderModules = std::move(shaderModules), device = device, descriptorSetLayout = descriptorSetLayout, pipelineLayout = pipelineLayout, descriptorPools = descriptorPools, computePipeline = computePipeline](){ - for (const auto pool : descriptorPools) { + for (const auto pool : descriptorPools) vkDestroyDescriptorPool(device, pool, nullptr); - } - for (const auto shaderModule : shaderModules) { + for (const auto shaderModule : shaderModules) vkDestroyShaderModule(device, shaderModule, nullptr); - } vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); vkDestroyPipelineLayout(device, pipelineLayout, nullptr); if (computePipeline != VK_NULL_HANDLE) @@ -211,19 +217,23 @@ void Shader::unloadVolatile() { descriptorSetsVector.clear(); } -const std::vector& Shader::getShaderStages() const { +const std::vector& Shader::getShaderStages() const +{ return shaderStages; } -const VkPipelineLayout Shader::getGraphicsPipelineLayout() const { +const VkPipelineLayout Shader::getGraphicsPipelineLayout() const +{ return pipelineLayout; } -VkPipeline Shader::getComputePipeline() const { +VkPipeline Shader::getComputePipeline() const +{ return computePipeline; } -static VkDescriptorImageInfo* createDescriptorImageInfo(graphics::Texture* texture, bool sampler) { +static VkDescriptorImageInfo* createDescriptorImageInfo(graphics::Texture* texture, bool sampler) +{ auto vkTexture = (Texture*)texture; auto imageInfo = new VkDescriptorImageInfo(); @@ -236,48 +246,52 @@ static VkDescriptorImageInfo* createDescriptorImageInfo(graphics::Texture* textu return imageInfo; } -void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frameIndex, VkPipelineBindPoint bindPoint) { +void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frameIndex, VkPipelineBindPoint bindPoint) +{ // detect whether a new frame has begun - if (currentFrame != frameIndex) { + if (currentFrame != frameIndex) + { currentFrame = frameIndex; currentUsedUniformStreamBuffersCount = 0; currentUsedDescriptorSetsCount = 0; // we needed more memory last frame, let's collapse all buffers into a single one. - if (streamBuffers.at(currentFrame).size() > 1) { + if (streamBuffers.at(currentFrame).size() > 1) + { size_t newSize = 0; - for (auto streamBuffer : streamBuffers.at(currentFrame)) { + for (auto streamBuffer : streamBuffers.at(currentFrame)) + { newSize += streamBuffer->getSize(); delete streamBuffer; } streamBuffers.at(currentFrame).clear(); - streamBuffers.at(currentFrame).push_back(new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, newSize)); + streamBuffers.at(currentFrame).push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, newSize)); } // no collapse necessary, can just call nextFrame to reset the current (only) streambuffer - else { + else streamBuffers.at(currentFrame).at(0)->nextFrame(); - } } // still the same frame - else { + else + { auto usedStreamBufferMemory = currentUsedUniformStreamBuffersCount * uniformBufferSizeAligned; - if (usedStreamBufferMemory >= streamBuffers.at(currentFrame).back()->getSize()) { + if (usedStreamBufferMemory >= streamBuffers.at(currentFrame).back()->getSize()) + { // we ran out of memory in the current frame, need to allocate more. - streamBuffers.at(currentFrame).push_back(new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned)); + streamBuffers.at(currentFrame).push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned)); currentUsedUniformStreamBuffersCount = 0; } } VkDescriptorSet currentDescriptorSet; - if (pfn_vkCmdPushDescriptorSetKHR) { + if (pfn_vkCmdPushDescriptorSetKHR) currentDescriptorSet = 0; - } - else { - if (currentUsedDescriptorSetsCount >= static_cast(descriptorSetsVector.at(currentFrame).size())) { + else + { + if (currentUsedDescriptorSetsCount >= static_cast(descriptorSetsVector.at(currentFrame).size())) descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet()); - } currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount); } @@ -350,14 +364,7 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frame } } - if (currentDescriptorSet) { - vkUpdateDescriptorSets(device, static_cast(descriptorWrite.size()), descriptorWrite.data(), 0, nullptr); - - vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, ¤tDescriptorSet, 0, nullptr); - - currentUsedDescriptorSetsCount++; - } - else { + if (pfn_vkCmdPushDescriptorSetKHR) pfn_vkCmdPushDescriptorSetKHR( commandBuffer, bindPoint, @@ -365,49 +372,63 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frame 0, static_cast(descriptorWrite.size()), descriptorWrite.data()); + else + { + vkUpdateDescriptorSets(device, static_cast(descriptorWrite.size()), descriptorWrite.data(), 0, nullptr); + + vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, ¤tDescriptorSet, 0, nullptr); + + currentUsedDescriptorSetsCount++; } - for (const auto imageInfo : imageInfos) { + for (const auto imageInfo : imageInfos) delete imageInfo; - } - if (bufferInfo) { + if (bufferInfo) delete bufferInfo; - } currentUsedUniformStreamBuffersCount++; } -Shader::~Shader() { +Shader::~Shader() +{ unloadVolatile(); } -void Shader::attach() { - if (!isCompute) { - if (Shader::current != this) { +void Shader::attach() +{ + if (!isCompute) + { + if (Shader::current != this) + { Graphics::flushBatchedDrawsGlobal(); Shader::current = this; Vulkan::shaderSwitch(); } } else - ((Graphics*)gfx)->setComputeShader(this); + vgfx->setComputeShader(this); } -int Shader::getVertexAttributeIndex(const std::string& name) { +int Shader::getVertexAttributeIndex(const std::string& name) +{ auto it = attributes.find(name); return it == attributes.end() ? -1 : it->second; } -const Shader::UniformInfo* Shader::getUniformInfo(const std::string& name) const { +const Shader::UniformInfo* Shader::getUniformInfo(const std::string& name) const +{ return &uniformInfos.at(name); } -const Shader::UniformInfo* Shader::getUniformInfo(BuiltinUniform builtin) const { +const Shader::UniformInfo* Shader::getUniformInfo(BuiltinUniform builtin) const +{ return builtinUniformInfo[builtin]; } -void Shader::sendTextures(const UniformInfo* info, graphics::Texture** textures, int count) { - for (unsigned i = 0; i < count; i++) { +void Shader::sendTextures(const UniformInfo* info, graphics::Texture** textures, int count) +{ + for (unsigned i = 0; i < count; i++) + { auto oldTexture = info->textures[i]; info->textures[i] = textures[i]; info->textures[i]->retain(); @@ -416,8 +437,8 @@ void Shader::sendTextures(const UniformInfo* info, graphics::Texture** textures, } } -void Shader::calculateUniformBufferSizeAligned() { - auto vgfx = (Graphics*)gfx; +void Shader::calculateUniformBufferSizeAligned() +{ auto minAlignment = vgfx->getMinUniformBufferOffsetAlignment(); size_t size = localUniformStagingData.size(); auto factor = static_cast(std::ceil( @@ -426,19 +447,22 @@ void Shader::calculateUniformBufferSizeAligned() { uniformBufferSizeAligned = factor * minAlignment; } -void Shader::buildLocalUniforms(spirv_cross::Compiler& comp, const spirv_cross::SPIRType& type, size_t baseoff, const std::string& basename) { +void Shader::buildLocalUniforms(spirv_cross::Compiler& comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename) +{ using namespace spirv_cross; const auto& membertypes = type.member_types; - for (size_t uindex = 0; uindex < membertypes.size(); uindex++) { + for (size_t uindex = 0; uindex < membertypes.size(); uindex++) + { const auto& memberType = comp.get_type(membertypes[uindex]); size_t memberSize = comp.get_declared_struct_member_size(type, uindex); size_t offset = baseoff + comp.type_struct_member_offset(type, uindex); std::string name = basename + comp.get_member_name(type.self, uindex); - switch (memberType.basetype) { + switch (memberType.basetype) + { case SPIRType::Struct: name += "."; buildLocalUniforms(comp, memberType, offset, name); @@ -458,49 +482,49 @@ void Shader::buildLocalUniforms(spirv_cross::Compiler& comp, const spirv_cross:: u.components = 1; u.data = localUniformStagingData.data() + offset; - if (memberType.columns == 1) { - if (memberType.basetype == SPIRType::Int) { + if (memberType.columns == 1) + { + if (memberType.basetype == SPIRType::Int) u.baseType = UNIFORM_INT; - } - else if (memberType.basetype == SPIRType::UInt) { + else if (memberType.basetype == SPIRType::UInt) u.baseType = UNIFORM_UINT; - } - else { + else u.baseType = UNIFORM_FLOAT; - } u.components = memberType.vecsize; } - else { + else + { u.baseType = UNIFORM_MATRIX; u.matrix.rows = memberType.vecsize; u.matrix.columns = memberType.columns; } const auto& reflectionIt = validationReflection.localUniforms.find(u.name); - if (reflectionIt != validationReflection.localUniforms.end()) { + if (reflectionIt != validationReflection.localUniforms.end()) + { const auto& localUniform = reflectionIt->second; const auto& values = localUniform.initializerValues; - if (!values.empty()) { + if (!values.empty()) memcpy( u.data, values.data(), std::min(u.dataSize, values.size() * sizeof(LocalUniformValue))); - } } uniformInfos[u.name] = u; BuiltinUniform builtin = BUILTIN_MAX_ENUM; - if (getConstant(u.name.c_str(), builtin)) { - if (builtin == BUILTIN_UNIFORMS_PER_DRAW) { + if (getConstant(u.name.c_str(), builtin)) + { + if (builtin == BUILTIN_UNIFORMS_PER_DRAW) builtinUniformDataOffset = offset; - } builtinUniformInfo[builtin] = &uniformInfos[u.name]; } } } -void Shader::compileShaders() { +void Shader::compileShaders() +{ using namespace glslang; using namespace spirv_cross; @@ -508,11 +532,10 @@ void Shader::compileShaders() { auto program = new TProgram(); - gfx = Module::getInstance(Module::ModuleType::M_GRAPHICS); - auto vgfx = (Graphics*)gfx; device = vgfx->getDevice(); - for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) { + for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) + { if (!stages[i]) continue; @@ -543,7 +566,8 @@ void Shader::compileShaders() { bool forceDefault = false; bool forwardCompat = true; - if (!tshader->parse(&defaultTBuiltInResource, defaultVersion, defaultProfile, forceDefault, forwardCompat, EShMsgSuppressWarnings)) { + if (!tshader->parse(&defaultTBuiltInResource, defaultVersion, defaultProfile, forceDefault, forwardCompat, EShMsgSuppressWarnings)) + { const char* msg1 = tshader->getInfoLog(); const char* msg2 = tshader->getInfoDebugLog(); @@ -554,17 +578,16 @@ void Shader::compileShaders() { glslangShaders.push_back(tshader); } - if (!program->link(EShMsgDefault)) { + if (!program->link(EShMsgDefault)) throw love::Exception("link failed! %s\n", program->getInfoLog()); - } - if (!program->mapIO()) { + if (!program->mapIO()) throw love::Exception("mapIO failed"); - } uniformInfos.clear(); - for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) { + for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) + { auto shaderStage = (ShaderStageType)i; auto glslangStage = getGlslShaderType(shaderStage); auto intermediate = program->getIntermediate(glslangStage); @@ -586,8 +609,7 @@ void Shader::compileShaders() { createInfo.codeSize = spirv.size() * sizeof(uint32_t); createInfo.pCode = spirv.data(); - Graphics* vkGfx = (Graphics*)gfx; - auto device = vkGfx->getDevice(); + auto device = vgfx->getDevice(); VkShaderModule shaderModule; @@ -612,8 +634,10 @@ void Shader::compileShaders() { auto shaderResources = comp.get_shader_resources(active); comp.set_enabled_interface_variables(std::move(active)); - for (const auto& resource : shaderResources.uniform_buffers) { - if (resource.name == "gl_DefaultUniformBlock") { + for (const auto& resource : shaderResources.uniform_buffers) + { + if (resource.name == "gl_DefaultUniformBlock") + { const auto& type = comp.get_type(resource.base_type_id); size_t uniformBufferObjectSize = comp.get_declared_struct_size(type); auto defaultUniformBlockSize = comp.get_declared_struct_size(type); @@ -625,12 +649,12 @@ void Shader::compileShaders() { std::string basename(""); buildLocalUniforms(comp, type, 0, basename); } - else { + else throw love::Exception("unimplemented: non default uniform blocks."); - } } - for (const auto& r : shaderResources.sampled_images) { + for (const auto& r : shaderResources.sampled_images) + { const SPIRType& basetype = comp.get_type(r.base_type_id); const SPIRType& type = comp.get_type(r.type_id); const SPIRType& imagetype = comp.get_type(basetype.image.type); @@ -643,7 +667,8 @@ void Shader::compileShaders() { info.isDepthSampler = type.image.depth; info.components = 1; - switch (imagetype.basetype) { + switch (imagetype.basetype) + { case SPIRType::Float: info.dataBaseType = DATA_BASETYPE_FLOAT; break; @@ -657,7 +682,8 @@ void Shader::compileShaders() { break; } - switch (basetype.image.dim) { + switch (basetype.image.dim) + { case spv::Dim2D: info.textureType = basetype.image.arrayed ? TEXTURE_2D_ARRAY : TEXTURE_2D; info.textures = new love::graphics::Texture * [info.count]; @@ -679,7 +705,8 @@ void Shader::compileShaders() { throw love::Exception("unknown dim"); } - if (info.baseType == UNIFORM_SAMPLER) { + if (info.baseType == UNIFORM_SAMPLER) + { auto tex = vgfx->getDefaultTexture(); for (int i = 0; i < info.count; i++) { info.textures[i] = tex; @@ -687,18 +714,17 @@ void Shader::compileShaders() { } } // fixme - else if (info.baseType == UNIFORM_TEXELBUFFER) { + else if (info.baseType == UNIFORM_TEXELBUFFER) throw love::Exception("texel buffers not supported yet"); - } uniformInfos[r.name] = info; BuiltinUniform builtin; - if (getConstant(r.name.c_str(), builtin)) { + if (getConstant(r.name.c_str(), builtin)) builtinUniformInfo[builtin] = &uniformInfos[info.name]; - } } - for (const auto& r : shaderResources.storage_buffers) { + for (const auto& r : shaderResources.storage_buffers) + { const auto& type = comp.get_type(r.type_id); UniformInfo u{}; @@ -709,27 +735,27 @@ void Shader::compileShaders() { u.location = comp.get_decoration(r.id, spv::DecorationBinding); const auto reflectionit = validationReflection.storageBuffers.find(u.name); - if (reflectionit != validationReflection.storageBuffers.end()) { + if (reflectionit != validationReflection.storageBuffers.end()) + { u.bufferStride = reflectionit->second.stride; u.bufferMemberCount = reflectionit->second.memberCount; u.access = reflectionit->second.access; } - else { + else continue; - } // todo: some stuff missing u.buffers = new love::graphics::Buffer * [u.count]; - for (int i = 0; i < u.count; i++) { + for (int i = 0; i < u.count; i++) u.buffers[i] = nullptr; - } uniformInfos[u.name] = u; } - for (const auto& r : shaderResources.storage_images) { + for (const auto& r : shaderResources.storage_images) + { const auto& type = comp.get_type(r.type_id); UniformInfo u{}; @@ -740,53 +766,53 @@ void Shader::compileShaders() { u.textures = new love::graphics::Texture * [u.count]; u.location = comp.get_decoration(r.id, spv::DecorationBinding); - for (int i = 0; i < u.count; i++) { + for (int i = 0; i < u.count; i++) u.textures[i] = nullptr; - } // some stuff missing ? uniformInfos[u.name] = u; } - if (shaderStage == SHADERSTAGE_VERTEX) { - for (const auto& r : shaderResources.stage_inputs) { + if (shaderStage == SHADERSTAGE_VERTEX) + for (const auto& r : shaderResources.stage_inputs) + { const auto& name = r.name; const int attributeLocation = static_cast(comp.get_decoration(r.id, spv::DecorationLocation)); attributes[name] = attributeLocation; } - } } delete program; - for (auto shader : glslangShaders) { + for (auto shader : glslangShaders) delete shader; - } } -void Shader::createDescriptorSetLayout() { +void Shader::createDescriptorSetLayout() +{ std::vector bindings; - for (auto const& [key, val] : uniformInfos) { + for (auto const& [key, val] : uniformInfos) + { auto type = Vulkan::getDescriptorType(val.baseType); - if (type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + if (type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) + { VkDescriptorSetLayoutBinding layoutBinding{}; layoutBinding.binding = val.location; layoutBinding.descriptorType = type; layoutBinding.descriptorCount = val.count; - if (isCompute) { + if (isCompute) layoutBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - } - else { + else layoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; - } bindings.push_back(layoutBinding); } } - if (!localUniformStagingData.empty()) { + if (!localUniformStagingData.empty()) + { VkDescriptorSetLayoutBinding uniformBinding{}; uniformBinding.binding = uniformLocation; uniformBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; @@ -805,23 +831,23 @@ void Shader::createDescriptorSetLayout() { if (pfn_vkCmdPushDescriptorSetKHR) layoutInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR; - if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) { + if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) throw love::Exception("failed to create descriptor set layout"); - } } -void Shader::createPipelineLayout() { +void Shader::createPipelineLayout() +{ VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = 1; pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout; pipelineLayoutInfo.pushConstantRangeCount = 0; - if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) { + if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) throw love::Exception("failed to create pipeline layout"); - } - if (isCompute) { + if (isCompute) + { assert(shaderStages.size() == 1); VkComputePipelineCreateInfo computeInfo{}; @@ -829,38 +855,39 @@ void Shader::createPipelineLayout() { computeInfo.stage = shaderStages.at(0); computeInfo.layout = pipelineLayout; - if (vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &computeInfo, nullptr, &computePipeline) != VK_SUCCESS) { + if (vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &computeInfo, nullptr, &computePipeline) != VK_SUCCESS) throw love::Exception("failed to create compute pipeline"); - } } } -void Shader::createStreamBuffers() { - auto vgfx = (Graphics*)gfx; +void Shader::createStreamBuffers() +{ const auto numImagesInFlight = vgfx->getNumImagesInFlight(); streamBuffers.resize(numImagesInFlight); - for (uint32_t i = 0; i < numImagesInFlight; i++) { - streamBuffers[i].push_back(new StreamBuffer(gfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned)); - } + for (uint32_t i = 0; i < numImagesInFlight; i++) + streamBuffers[i].push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned)); } -void Shader::setVideoTextures(graphics::Texture* ytexture, graphics::Texture* cbtexture, graphics::Texture* crtexture) { +void Shader::setVideoTextures(graphics::Texture* ytexture, graphics::Texture* cbtexture, graphics::Texture* crtexture) +{ // if the shader doesn't actually use these textures they might get optimized out // in that case this function becomes a noop. - if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y] != nullptr) { + if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y] != nullptr) + { auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y]->textures[0]; ytexture->retain(); oldTexture->release(); builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_Y]->textures[0] = ytexture; - } - if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB] != nullptr) { + if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB] != nullptr) + { auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB]->textures[0]; cbtexture->retain(); oldTexture->release(); builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CB]->textures[0] = cbtexture; } - if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CR] != nullptr) { + if (builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CR] != nullptr) + { auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_VIDEO_CR]->textures[0]; crtexture->retain(); oldTexture->release(); @@ -868,19 +895,23 @@ void Shader::setVideoTextures(graphics::Texture* ytexture, graphics::Texture* cb } } -bool Shader::hasUniform(const std::string& name) const { +bool Shader::hasUniform(const std::string& name) const +{ return uniformInfos.find(name) != uniformInfos.end(); } -void Shader::setUniformData(BuiltinUniformData& data) { +void Shader::setUniformData(BuiltinUniformData& data) +{ char* ptr = (char*) builtinUniformInfo[BUILTIN_UNIFORMS_PER_DRAW]->data + builtinUniformDataOffset; memcpy(ptr, &data, sizeof(BuiltinUniformData)); } -void Shader::setMainTex(graphics::Texture* texture) { +void Shader::setMainTex(graphics::Texture* texture) +{ // if the shader doesn't actually use the texture it might get optimized out // in that case this function becomes a noop. - if (builtinUniformInfo[BUILTIN_TEXTURE_MAIN] != nullptr) { + if (builtinUniformInfo[BUILTIN_TEXTURE_MAIN] != nullptr) + { auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0]; texture->retain(); oldTexture->release(); @@ -888,8 +919,10 @@ void Shader::setMainTex(graphics::Texture* texture) { } } -VkDescriptorSet Shader::allocateDescriptorSet() { - if (freeDescriptorSets.empty()) { +VkDescriptorSet Shader::allocateDescriptorSet() +{ + if (freeDescriptorSets.empty()) + { // fixme: we can optimize this, since sizes should never change for a given shader. std::vector sizes; @@ -899,7 +932,8 @@ VkDescriptorSet Shader::allocateDescriptorSet() { sizes.push_back(size); - for (const auto& [key, val] : uniformInfos) { + for (const auto& [key, val] : uniformInfos) + { VkDescriptorPoolSize size{}; auto type = Vulkan::getDescriptorType(val.baseType); if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { @@ -917,9 +951,8 @@ VkDescriptorSet Shader::allocateDescriptorSet() { createInfo.pPoolSizes = sizes.data(); VkDescriptorPool pool; - if (vkCreateDescriptorPool(device, &createInfo, nullptr, &pool) != VK_SUCCESS) { + if (vkCreateDescriptorPool(device, &createInfo, nullptr, &pool) != VK_SUCCESS) throw love::Exception("failed to create descriptor pool"); - } descriptorPools.push_back(pool); std::vector layouts(DESCRIPTOR_POOL_SIZE, descriptorSetLayout); @@ -933,19 +966,18 @@ VkDescriptorSet Shader::allocateDescriptorSet() { std::vector descriptorSet; descriptorSet.resize(DESCRIPTOR_POOL_SIZE); VkResult result = vkAllocateDescriptorSets(device, &allocInfo, descriptorSet.data()); - if (result != VK_SUCCESS) { + if (result != VK_SUCCESS) throw love::Exception("failed to allocate descriptor set"); - } - for (const auto ds : descriptorSet) { + for (const auto ds : descriptorSet) freeDescriptorSets.push(ds); - } } auto ds = freeDescriptorSets.front(); freeDescriptorSets.pop(); return ds; } + } // vulkan } // graphics } // love diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index 63a44bd70..3e732ad6d 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -1,13 +1,15 @@ -#ifndef LOVE_GRAPHICS_VULKAN_SHADER_H -#define LOVE_GRAPHICS_VULKAN_SHADER_H +#pragma once +// LÖVE #include #include #include "Vulkan.h" +// Libraries #include "VulkanWrapper.h" #include "libraries/spirv_cross/spirv_reflect.hpp" +// C++ #include #include #include @@ -15,10 +17,19 @@ #include -namespace love { -namespace graphics { -namespace vulkan { -class Shader final : public graphics::Shader, public Volatile { +namespace love +{ +namespace graphics +{ +namespace vulkan +{ + +class Graphics; + +class Shader final + : public graphics::Shader + , public Volatile +{ public: Shader(StrongRef stages[]); virtual ~Shader(); @@ -94,7 +105,8 @@ private: std::vector shaderStages; std::vector shaderModules; - Graphics* gfx; + + Graphics *vgfx = nullptr; VkDevice device; bool isCompute = false; @@ -113,8 +125,7 @@ private: uint32_t currentUsedUniformStreamBuffersCount; uint32_t currentUsedDescriptorSetsCount; }; -} -} -} -#endif +} +} +} diff --git a/src/modules/graphics/vulkan/ShaderStage.cpp b/src/modules/graphics/vulkan/ShaderStage.cpp index b8a313d77..650410412 100644 --- a/src/modules/graphics/vulkan/ShaderStage.cpp +++ b/src/modules/graphics/vulkan/ShaderStage.cpp @@ -1,23 +1,29 @@ #include "ShaderStage.h" - #include "Graphics.h" #include "libraries/glslang/glslang/Public/ShaderLang.h" #include "libraries/glslang/SPIRV/GlslangToSpv.h" -#include #include - #include +namespace love +{ +namespace graphics +{ +namespace vulkan +{ -namespace love { -namespace graphics { -namespace vulkan { -ShaderStage::ShaderStage(love::graphics::Graphics* gfx, ShaderStageType stage, const std::string& glsl, bool gles, const std::string& cachekey) +ShaderStage::ShaderStage(love::graphics::Graphics *gfx, ShaderStageType stage, const std::string &glsl, bool gles, const std::string &cachekey) : love::graphics::ShaderStage(gfx, stage, glsl, gles, cachekey) { // the compilation is done in Shader. } + +ptrdiff_t ShaderStage::getHandle() const +{ + return 0; +} + } // love } // graphics } // vulkan diff --git a/src/modules/graphics/vulkan/ShaderStage.h b/src/modules/graphics/vulkan/ShaderStage.h index 00ac7e0ca..cf1b55a1e 100644 --- a/src/modules/graphics/vulkan/ShaderStage.h +++ b/src/modules/graphics/vulkan/ShaderStage.h @@ -1,24 +1,25 @@ -#ifndef LOVE_GRAPHICS_VULKAN_SHADERSTAGE_H -#define LOVE_GRAPHICS_VULKAN_SHADERSTAGE_H +#pragma once #include "graphics/ShaderStage.h" #include "modules/graphics/Graphics.h" #include "VulkanWrapper.h" -namespace love { -namespace graphics { -namespace vulkan { -class ShaderStage final : public graphics::ShaderStage { +namespace love +{ +namespace graphics +{ +namespace vulkan +{ + +class ShaderStage final : public graphics::ShaderStage +{ public: - ShaderStage(love::graphics::Graphics* gfx, ShaderStageType stage, const std::string& glsl, bool gles, const std::string& cachekey); + ShaderStage(love::graphics::Graphics *gfx, ShaderStageType stage, const std::string &glsl, bool gles, const std::string &cachekey); - ptrdiff_t getHandle() const { - return 0; - } + ptrdiff_t getHandle() const override; }; -} -} -} -#endif +} +} +} diff --git a/src/modules/graphics/vulkan/StreamBuffer.cpp b/src/modules/graphics/vulkan/StreamBuffer.cpp index 29e86b499..1e261b84a 100644 --- a/src/modules/graphics/vulkan/StreamBuffer.cpp +++ b/src/modules/graphics/vulkan/StreamBuffer.cpp @@ -3,11 +3,17 @@ #include "Graphics.h" -namespace love { -namespace graphics { -namespace vulkan { -static VkBufferUsageFlags getUsageFlags(BufferUsage mode) { - switch (mode) { +namespace love +{ +namespace graphics +{ +namespace vulkan +{ + +static VkBufferUsageFlags getUsageFlags(BufferUsage mode) +{ + switch (mode) + { case BUFFERUSAGE_VERTEX: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; case BUFFERUSAGE_INDEX: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT; case BUFFERUSAGE_UNIFORM: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; @@ -16,13 +22,15 @@ static VkBufferUsageFlags getUsageFlags(BufferUsage mode) { } } -StreamBuffer::StreamBuffer(graphics::Graphics* gfx, BufferUsage mode, size_t size) - : love::graphics::StreamBuffer(mode, size), gfx(gfx) { +StreamBuffer::StreamBuffer(graphics::Graphics *gfx, BufferUsage mode, size_t size) + : love::graphics::StreamBuffer(mode, size) + , vgfx(dynamic_cast(gfx)) +{ loadVolatile(); } -bool StreamBuffer::loadVolatile() { - Graphics* vgfx = (Graphics*)gfx; +bool StreamBuffer::loadVolatile() +{ allocator = vgfx->getVmaAllocator(); VkBufferCreateInfo bufferInfo{}; @@ -42,37 +50,48 @@ bool StreamBuffer::loadVolatile() { return true; } -void StreamBuffer::unloadVolatile() { +void StreamBuffer::unloadVolatile() +{ if (buffer == VK_NULL_HANDLE) return; - auto vgfx = (Graphics*)gfx; vgfx->queueCleanUp([allocator=allocator, buffer=buffer, allocation=allocation](){ vmaDestroyBuffer(allocator, buffer, allocation); }); buffer = VK_NULL_HANDLE; } -StreamBuffer::~StreamBuffer() { +StreamBuffer::~StreamBuffer() +{ unloadVolatile(); } -love::graphics::StreamBuffer::MapInfo StreamBuffer::map(size_t minsize) { +ptrdiff_t StreamBuffer::getHandle() const +{ + return (ptrdiff_t) buffer; +} + +love::graphics::StreamBuffer::MapInfo StreamBuffer::map(size_t minsize) +{ (void)minsize; return love::graphics::StreamBuffer::MapInfo((uint8*) allocInfo.pMappedData + usedGPUMemory, getSize()); } -size_t StreamBuffer::unmap(size_t usedSize) { +size_t StreamBuffer::unmap(size_t usedSize) +{ return usedGPUMemory; } -void StreamBuffer::markUsed(size_t usedSize) { +void StreamBuffer::markUsed(size_t usedSize) +{ usedGPUMemory += usedSize; } -void StreamBuffer::nextFrame() { +void StreamBuffer::nextFrame() +{ usedGPUMemory = 0; } + } // vulkan } // graphics } // love diff --git a/src/modules/graphics/vulkan/StreamBuffer.h b/src/modules/graphics/vulkan/StreamBuffer.h index a89a2082c..8df9e0f2c 100644 --- a/src/modules/graphics/vulkan/StreamBuffer.h +++ b/src/modules/graphics/vulkan/StreamBuffer.h @@ -1,5 +1,4 @@ -#ifndef LOVE_GRAPHICS_VULKAN_STREAMBUFFER_H -#define LOVE_GRAPHICS_VULKAN_STREAMBUFFER_H +#pragma once #include "graphics/Volatile.h" #include "modules/graphics/StreamBuffer.h" @@ -7,12 +6,21 @@ #include "VulkanWrapper.h" -namespace love { -namespace graphics { -namespace vulkan { -class StreamBuffer : public love::graphics::StreamBuffer, public graphics::Volatile { +namespace love +{ +namespace graphics +{ +namespace vulkan +{ + +class Graphics; + +class StreamBuffer + : public love::graphics::StreamBuffer + , public graphics::Volatile +{ public: - StreamBuffer(graphics::Graphics* gfx, BufferUsage mode, size_t size); + StreamBuffer(graphics::Graphics *gfx, BufferUsage mode, size_t size); virtual ~StreamBuffer(); virtual bool loadVolatile() override; @@ -25,12 +33,10 @@ public: void nextFrame() override; - ptrdiff_t getHandle() const override { - return (ptrdiff_t) buffer; - } + ptrdiff_t getHandle() const override; private: - graphics::Graphics* gfx; + Graphics *vgfx = nullptr; VmaAllocator allocator; VmaAllocation allocation; VmaAllocationInfo allocInfo; @@ -38,8 +44,7 @@ private: size_t usedGPUMemory; }; + } // vulkan } // graphics } // love - -#endif diff --git a/src/modules/graphics/vulkan/Texture.cpp b/src/modules/graphics/vulkan/Texture.cpp index 8e29a899e..29d7e3c61 100644 --- a/src/modules/graphics/vulkan/Texture.cpp +++ b/src/modules/graphics/vulkan/Texture.cpp @@ -4,22 +4,26 @@ #include -// make vulkan::Graphics functions available -#define vgfx ((Graphics*)gfx) +namespace love +{ +namespace graphics +{ +namespace vulkan +{ -namespace love { -namespace graphics { -namespace vulkan { -Texture::Texture(love::graphics::Graphics* gfx, const Settings& settings, const Slices* data) - : love::graphics::Texture(gfx, settings, data), gfx(gfx), slices(settings.type) { - if (data) { +Texture::Texture(love::graphics::Graphics *gfx, const Settings &settings, const Slices *data) + : love::graphics::Texture(gfx, settings, data) + , vgfx(dynamic_cast(gfx)) + , slices(settings.type) +{ + if (data) slices = *data; - } loadVolatile(); } -bool Texture::loadVolatile() { +bool Texture::loadVolatile() +{ allocator = vgfx->getVmaAllocator(); device = vgfx->getDevice(); @@ -44,10 +48,10 @@ bool Texture::loadVolatile() { layerCount = 1; - if (texType == TEXTURE_2D_ARRAY) { + if (texType == TEXTURE_2D_ARRAY) layerCount = getLayerCount(); - } - else if (texType == TEXTURE_CUBE) { + else if (texType == TEXTURE_CUBE) + { layerCount = 6; createFlags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; } @@ -70,9 +74,8 @@ bool Texture::loadVolatile() { VmaAllocationCreateInfo imageAllocationCreateInfo{}; - if (vmaCreateImage(allocator, &imageInfo, &imageAllocationCreateInfo, &textureImage, &textureImageAllocation, nullptr) != VK_SUCCESS) { + if (vmaCreateImage(allocator, &imageInfo, &imageAllocationCreateInfo, &textureImage, &textureImageAllocation, nullptr) != VK_SUCCESS) throw love::Exception("failed to create image"); - } auto commandBuffer = vgfx->getDataTransferCommandBuffer(); @@ -90,37 +93,36 @@ bool Texture::loadVolatile() { bool hasdata = slices.get(0, 0) != nullptr; - if (hasdata) { - for (int mip = 0; mip < layerCount; mip++) { + if (hasdata) + for (int mip = 0; mip < layerCount; mip++) + { // fixme: deal with compressed images. int sliceCount; - if (texType == TEXTURE_CUBE) { + if (texType == TEXTURE_CUBE) sliceCount = 6; - } else { + else sliceCount = slices.getSliceCount(); - } - for (int slice = 0; slice < sliceCount; slice++) { + for (int slice = 0; slice < sliceCount; slice++) + { auto* id = slices.get(slice, mip); - if (id != nullptr) { + if (id != nullptr) uploadImageData(id, mip, slice, 0, 0); - } } } - } else { + else clear(); - } createTextureImageView(); textureSampler = vgfx->getCachedSampler(samplerState); - if (slices.getMipmapCount() <= 1 && getMipmapsMode() != MIPMAPS_NONE) { + if (slices.getMipmapCount() <= 1 && getMipmapsMode() != MIPMAPS_NONE) generateMipmaps(); - } return true; } -void Texture::unloadVolatile() { +void Texture::unloadVolatile() +{ if (textureImage == VK_NULL_HANDLE) return; @@ -137,20 +139,44 @@ void Texture::unloadVolatile() { textureImage = VK_NULL_HANDLE; } -Texture::~Texture() { +Texture::~Texture() +{ unloadVolatile(); } -void Texture::setSamplerState(const SamplerState &s) { +ptrdiff_t Texture::getRenderTargetHandle() const +{ + return (ptrdiff_t)textureImageView; +} + +ptrdiff_t Texture::getSamplerHandle() const +{ + return (ptrdiff_t)textureSampler; +} + +int Texture::getMSAA() const +{ + return 0; +} + +ptrdiff_t Texture::getHandle() const +{ + return (ptrdiff_t)textureImage; +} + +void Texture::setSamplerState(const SamplerState &s) +{ love::graphics::Texture::setSamplerState(s); textureSampler = vgfx->getCachedSampler(s); } -VkImageLayout Texture::getImageLayout() const { +VkImageLayout Texture::getImageLayout() const +{ return imageLayout; } -void Texture::createTextureImageView() { +void Texture::createTextureImageView() +{ auto vulkanFormat = Vulkan::getTextureFormat(format); VkImageViewCreateInfo viewInfo{}; @@ -168,12 +194,12 @@ void Texture::createTextureImageView() { viewInfo.components.b = vulkanFormat.swizzleB; viewInfo.components.a = vulkanFormat.swizzleA; - if (vkCreateImageView(device, &viewInfo, nullptr, &textureImageView) != VK_SUCCESS) { + if (vkCreateImageView(device, &viewInfo, nullptr, &textureImageView) != VK_SUCCESS) throw love::Exception("could not create texture image view"); - } } -void Texture::clear() { +void Texture::clear() +{ auto commandBuffer = vgfx->getDataTransferCommandBuffer(); auto clearColor = getClearValue(); @@ -185,7 +211,8 @@ void Texture::clear() { range.baseArrayLayer = 0; range.layerCount = VK_REMAINING_ARRAY_LAYERS; - if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) { + if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) + { Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, range.levelCount, 0, range.layerCount); @@ -196,16 +223,17 @@ void Texture::clear() { VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0, range.levelCount, 0, range.layerCount); } - else { + else vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &range); - } } -VkClearColorValue Texture::getClearValue() { +VkClearColorValue Texture::getClearValue() +{ auto vulkanFormat = Vulkan::getTextureFormat(format); VkClearColorValue clearColor{}; - switch (vulkanFormat.internalFormatRepresentation) { + switch (vulkanFormat.internalFormatRepresentation) + { case FORMATREPRESENTATION_FLOAT: clearColor.float32[0] = 0.0f; clearColor.float32[1] = 0.0f; @@ -228,7 +256,8 @@ VkClearColorValue Texture::getClearValue() { return clearColor; } -void Texture::generateMipmapsInternal() { +void Texture::generateMipmapsInternal() +{ auto commandBuffer = vgfx->getDataTransferCommandBuffer(); if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) @@ -249,7 +278,8 @@ void Texture::generateMipmapsInternal() { uint32_t mipLevels = static_cast(getMipmapCount()); - for (uint32_t i = 1; i < mipLevels; i++) { + for (uint32_t i = 1; i < mipLevels; i++) + { barrier.subresourceRange.baseMipLevel = i - 1; barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; @@ -309,7 +339,8 @@ void Texture::generateMipmapsInternal() { 1, &barrier); } -void Texture::uploadByteData(PixelFormat pixelformat, const void* data, size_t size, int level, int slice, const Rect& r) { +void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) +{ VkBuffer stagingBuffer; VmaAllocation vmaAllocation; @@ -346,7 +377,8 @@ void Texture::uploadByteData(PixelFormat pixelformat, const void* data, size_t s auto commandBuffer = vgfx->getDataTransferCommandBuffer(); - if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) { + if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) + { Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, level, 1, slice, 1); @@ -365,7 +397,7 @@ void Texture::uploadByteData(PixelFormat pixelformat, const void* data, size_t s VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, level, 1, slice, 1); } - else { + else vkCmdCopyBufferToImage( commandBuffer, stagingBuffer, @@ -374,14 +406,14 @@ void Texture::uploadByteData(PixelFormat pixelformat, const void* data, size_t s 1, ®ion ); - } vgfx->queueCleanUp([allocator = allocator, stagingBuffer, vmaAllocation]() { vmaDestroyBuffer(allocator, stagingBuffer, vmaAllocation); }); } -void Texture::copyFromBuffer(graphics::Buffer* source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect& rect) { +void Texture::copyFromBuffer(graphics::Buffer *source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect &rect) +{ auto commandBuffer = vgfx->getDataTransferCommandBuffer(); VkImageSubresourceLayers layers{}; @@ -398,7 +430,8 @@ void Texture::copyFromBuffer(graphics::Buffer* source, size_t sourceoffset, int region.imageExtent.width = static_cast(rect.w); region.imageExtent.height = static_cast(rect.h); - if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) { + if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) + { Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); @@ -409,7 +442,8 @@ void Texture::copyFromBuffer(graphics::Buffer* source, size_t sourceoffset, int vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), textureImage, VK_IMAGE_LAYOUT_GENERAL, 1, ®ion); } -void Texture::copyToBuffer(graphics::Buffer* dest, int slice, int mipmap, const Rect& rect, size_t destoffset, int destwidth, size_t size) { +void Texture::copyToBuffer(graphics::Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth, size_t size) +{ auto commandBuffer = vgfx->getReadbackCommandBuffer(); VkImageSubresourceLayers layers{}; @@ -427,7 +461,8 @@ void Texture::copyToBuffer(graphics::Buffer* dest, int slice, int mipmap, const region.imageExtent.height = static_cast(rect.h); region.imageExtent.depth = 1; - if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) { + if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) + { Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); vkCmdCopyImageToBuffer(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, (VkBuffer) dest->getHandle(), 1, ®ion); diff --git a/src/modules/graphics/vulkan/Texture.h b/src/modules/graphics/vulkan/Texture.h index 7f4a783dd..2f9e845a5 100644 --- a/src/modules/graphics/vulkan/Texture.h +++ b/src/modules/graphics/vulkan/Texture.h @@ -1,20 +1,26 @@ -#ifndef LOVE_GRAPHICS_VULKAN_TEXTURE_H -#define LOVE_GRAPHICS_VULKAN_TEXTURE_H +#pragma once #include "graphics/Texture.h" #include "graphics/Volatile.h" #include "VulkanWrapper.h" -#include +namespace love +{ +namespace graphics +{ +namespace vulkan +{ -namespace love { -namespace graphics { -namespace vulkan { -class Texture : public graphics::Texture, public Volatile { +class Graphics; + +class Texture + : public graphics::Texture + , public Volatile +{ public: - Texture(love::graphics::Graphics* gfx, const Settings& settings, const Slices* data); + Texture(love::graphics::Graphics *gfx, const Settings &settings, const Slices *data); ~Texture(); virtual bool loadVolatile() override; @@ -24,18 +30,18 @@ public: VkImageLayout getImageLayout() const; - void copyFromBuffer(graphics::Buffer* source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect& rect) override; - void copyToBuffer(graphics::Buffer* dest, int slice, int mipmap, const Rect& rect, size_t destoffset, int destwidth, size_t size) override; + void copyFromBuffer(graphics::Buffer *source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect &rect) override; + void copyToBuffer(graphics::Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth, size_t size) override; - ptrdiff_t getRenderTargetHandle() const override { return (ptrdiff_t)textureImageView; }; - ptrdiff_t getSamplerHandle() const override { return (ptrdiff_t)textureSampler; }; + ptrdiff_t getRenderTargetHandle() const override; + ptrdiff_t getSamplerHandle() const override; - void uploadByteData(PixelFormat pixelformat, const void* data, size_t size, int level, int slice, const Rect& r) override; + void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) override; void generateMipmapsInternal() override; - int getMSAA() const override { return 0; }; - ptrdiff_t getHandle() const override { return (ptrdiff_t)textureImage; } + int getMSAA() const override; + ptrdiff_t getHandle() const override; private: void createTextureImageView(); @@ -43,7 +49,7 @@ private: VkClearColorValue getClearValue(); - graphics::Graphics* gfx = nullptr; + Graphics *vgfx = nullptr; VkDevice device = VK_NULL_HANDLE; VmaAllocator allocator = VK_NULL_HANDLE; VkImage textureImage = VK_NULL_HANDLE; @@ -54,8 +60,7 @@ private: Slices slices; int layerCount = 0; }; + } // vulkan } // graphics } // love - -#endif diff --git a/src/modules/graphics/vulkan/Vulkan.cpp b/src/modules/graphics/vulkan/Vulkan.cpp index c993a80e5..363310847 100644 --- a/src/modules/graphics/vulkan/Vulkan.cpp +++ b/src/modules/graphics/vulkan/Vulkan.cpp @@ -3,34 +3,45 @@ #include -namespace love { -namespace graphics { -namespace vulkan { +namespace love +{ +namespace graphics +{ +namespace vulkan +{ + static uint32_t numShaderSwitches; static int vsync = 1; -void Vulkan::shaderSwitch() { +void Vulkan::shaderSwitch() +{ numShaderSwitches++; } -uint32_t Vulkan::getNumShaderSwitches() { +uint32_t Vulkan::getNumShaderSwitches() +{ return numShaderSwitches; } -void Vulkan::resetShaderSwitches() { +void Vulkan::resetShaderSwitches() +{ numShaderSwitches = 0; } -void Vulkan::setVsync(int value) { +void Vulkan::setVsync(int value) +{ vsync = value; } -int Vulkan::getVsync() { +int Vulkan::getVsync() +{ return vsync; } -VkFormat Vulkan::getVulkanVertexFormat(DataFormat format) { - switch (format) { +VkFormat Vulkan::getVulkanVertexFormat(DataFormat format) +{ + switch (format) + { case DATAFORMAT_FLOAT: return VK_FORMAT_R32_SFLOAT; case DATAFORMAT_FLOAT_VEC2: @@ -110,10 +121,12 @@ VkFormat Vulkan::getVulkanVertexFormat(DataFormat format) { } } -TextureFormat Vulkan::getTextureFormat(PixelFormat format) { +TextureFormat Vulkan::getTextureFormat(PixelFormat format) +{ TextureFormat textureFormat{}; - switch (format) { + switch (format) + { case PIXELFORMAT_UNKNOWN: throw love::Exception("unknown pixel format"); case PIXELFORMAT_NORMAL: @@ -353,8 +366,10 @@ TextureFormat Vulkan::getTextureFormat(PixelFormat format) { // values taken from https://pcisig.com/membership/member-companies // as specified at https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html -std::string Vulkan::getVendorName(uint32_t vendorId) { - switch (vendorId) { +std::string Vulkan::getVendorName(uint32_t vendorId) +{ + switch (vendorId) + { case 4130: return "AMD"; case 4318: @@ -376,7 +391,8 @@ std::string Vulkan::getVendorName(uint32_t vendorId) { } } -std::string Vulkan::getVulkanApiVersion(uint32_t version) { +std::string Vulkan::getVulkanApiVersion(uint32_t version) +{ std::stringstream ss; ss << VK_API_VERSION_MAJOR(version) @@ -386,8 +402,10 @@ std::string Vulkan::getVulkanApiVersion(uint32_t version) { return ss.str(); } -VkPrimitiveTopology Vulkan::getPrimitiveTypeTopology(graphics::PrimitiveType primitiveType) { - switch (primitiveType) { +VkPrimitiveTopology Vulkan::getPrimitiveTypeTopology(graphics::PrimitiveType primitiveType) +{ + switch (primitiveType) + { case PRIMITIVE_POINTS: return VK_PRIMITIVE_TOPOLOGY_POINT_LIST; case PRIMITIVE_TRIANGLES: @@ -401,8 +419,10 @@ VkPrimitiveTopology Vulkan::getPrimitiveTypeTopology(graphics::PrimitiveType pri } } -VkBlendFactor Vulkan::getBlendFactor(BlendFactor blendFactor) { - switch (blendFactor) { +VkBlendFactor Vulkan::getBlendFactor(BlendFactor blendFactor) +{ + switch (blendFactor) + { case BLENDFACTOR_ZERO: return VK_BLEND_FACTOR_ZERO; case BLENDFACTOR_ONE: @@ -430,8 +450,10 @@ VkBlendFactor Vulkan::getBlendFactor(BlendFactor blendFactor) { } } -VkBlendOp Vulkan::getBlendOp(BlendOperation op) { - switch (op) { +VkBlendOp Vulkan::getBlendOp(BlendOperation op) +{ + switch (op) + { case BLENDOP_ADD: return VK_BLEND_OP_ADD; case BLENDOP_MAX: @@ -447,35 +469,34 @@ VkBlendOp Vulkan::getBlendOp(BlendOperation op) { } } -VkBool32 Vulkan::getBool(bool b) { - if (b) { +VkBool32 Vulkan::getBool(bool b) +{ + if (b) return VK_TRUE; - } else { + else return VK_FALSE; - } } -VkColorComponentFlags Vulkan::getColorMask(ColorChannelMask mask) { +VkColorComponentFlags Vulkan::getColorMask(ColorChannelMask mask) +{ VkColorComponentFlags flags = 0; - if (mask.r) { + if (mask.r) flags |= VK_COLOR_COMPONENT_R_BIT; - } - if (mask.g) { + if (mask.g) flags |= VK_COLOR_COMPONENT_G_BIT; - } - if (mask.b) { + if (mask.b) flags |= VK_COLOR_COMPONENT_B_BIT; - } - if (mask.a) { + if (mask.a) flags |= VK_COLOR_COMPONENT_A_BIT; - } return flags; } -VkFrontFace Vulkan::getFrontFace(Winding winding) { - switch (winding) { +VkFrontFace Vulkan::getFrontFace(Winding winding) +{ + switch (winding) + { case WINDING_CW: return VK_FRONT_FACE_CLOCKWISE; case WINDING_CCW: @@ -485,8 +506,10 @@ VkFrontFace Vulkan::getFrontFace(Winding winding) { } } -VkCullModeFlags Vulkan::getCullMode(CullMode cullmode) { - switch (cullmode) { +VkCullModeFlags Vulkan::getCullMode(CullMode cullmode) +{ + switch (cullmode) + { case CULL_BACK: return VK_CULL_MODE_BACK_BIT; case CULL_FRONT: @@ -498,8 +521,10 @@ VkCullModeFlags Vulkan::getCullMode(CullMode cullmode) { } } -VkImageType Vulkan::getImageType(TextureType textureType) { - switch (textureType) { +VkImageType Vulkan::getImageType(TextureType textureType) +{ + switch (textureType) + { case TEXTURE_2D: case TEXTURE_2D_ARRAY: case TEXTURE_CUBE: @@ -511,8 +536,10 @@ VkImageType Vulkan::getImageType(TextureType textureType) { } } -VkImageViewType Vulkan::getImageViewType(TextureType textureType) { - switch (textureType) { +VkImageViewType Vulkan::getImageViewType(TextureType textureType) +{ + switch (textureType) + { case TEXTURE_2D: return VK_IMAGE_VIEW_TYPE_2D; case TEXTURE_2D_ARRAY: @@ -526,16 +553,18 @@ VkImageViewType Vulkan::getImageViewType(TextureType textureType) { } } -VkPolygonMode Vulkan::getPolygonMode(bool wireframe) { - if (wireframe) { +VkPolygonMode Vulkan::getPolygonMode(bool wireframe) +{ + if (wireframe) return VK_POLYGON_MODE_LINE; - } else { + else return VK_POLYGON_MODE_FILL; - } } -VkFilter Vulkan::getFilter(SamplerState::FilterMode mode) { - switch (mode) { +VkFilter Vulkan::getFilter(SamplerState::FilterMode mode) +{ + switch (mode) + { case SamplerState::FILTER_LINEAR: return VK_FILTER_LINEAR; case SamplerState::FILTER_NEAREST: @@ -545,8 +574,10 @@ VkFilter Vulkan::getFilter(SamplerState::FilterMode mode) { } } -VkSamplerAddressMode Vulkan::getWrapMode(SamplerState::WrapMode mode) { - switch (mode) { +VkSamplerAddressMode Vulkan::getWrapMode(SamplerState::WrapMode mode) +{ + switch (mode) + { //fixme: not accounting for different clamps (how does that work in vulkan?) case SamplerState::WRAP_CLAMP: case SamplerState::WRAP_CLAMP_ZERO: @@ -561,8 +592,10 @@ VkSamplerAddressMode Vulkan::getWrapMode(SamplerState::WrapMode mode) { } } -VkCompareOp Vulkan::getCompareOp(CompareMode mode) { - switch (mode) { +VkCompareOp Vulkan::getCompareOp(CompareMode mode) +{ + switch (mode) + { case COMPARE_LESS: return VK_COMPARE_OP_LESS; case COMPARE_LEQUAL: @@ -584,8 +617,10 @@ VkCompareOp Vulkan::getCompareOp(CompareMode mode) { } } -VkSamplerMipmapMode Vulkan::getMipMapMode(SamplerState::MipmapFilterMode mode) { - switch (mode) { +VkSamplerMipmapMode Vulkan::getMipMapMode(SamplerState::MipmapFilterMode mode) +{ + switch (mode) + { case SamplerState::MIPMAP_FILTER_NEAREST: return VK_SAMPLER_MIPMAP_MODE_NEAREST; case SamplerState::MIPMAP_FILTER_NONE: @@ -595,9 +630,10 @@ VkSamplerMipmapMode Vulkan::getMipMapMode(SamplerState::MipmapFilterMode mode) { } } - -VkDescriptorType Vulkan::getDescriptorType(graphics::Shader::UniformType type) { - switch (type) { +VkDescriptorType Vulkan::getDescriptorType(graphics::Shader::UniformType type) +{ + switch (type) + { case graphics::Shader::UniformType::UNIFORM_FLOAT: case graphics::Shader::UniformType::UNIFORM_MATRIX: case graphics::Shader::UniformType::UNIFORM_INT: @@ -617,8 +653,10 @@ VkDescriptorType Vulkan::getDescriptorType(graphics::Shader::UniformType type) { } } -VkStencilOp Vulkan::getStencilOp(StencilAction action) { - switch (action) { +VkStencilOp Vulkan::getStencilOp(StencilAction action) +{ + switch (action) + { case STENCIL_KEEP: return VK_STENCIL_OP_KEEP; case STENCIL_ZERO: @@ -640,8 +678,10 @@ VkStencilOp Vulkan::getStencilOp(StencilAction action) { } } -VkIndexType Vulkan::getVulkanIndexBufferType(IndexDataType type) { - switch (type) { +VkIndexType Vulkan::getVulkanIndexBufferType(IndexDataType type) +{ + switch (type) + { case INDEX_UINT16: return VK_INDEX_TYPE_UINT16; case INDEX_UINT32: return VK_INDEX_TYPE_UINT32; default: @@ -650,7 +690,8 @@ VkIndexType Vulkan::getVulkanIndexBufferType(IndexDataType type) { } void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, - uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount) { + uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount) +{ VkImageMemoryBarrier barrier{}; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; barrier.oldLayout = oldLayout; @@ -667,63 +708,72 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima VkPipelineStageFlags sourceStage; VkPipelineStageFlags destinationStage; - if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + { barrier.srcAccessMask = 0; barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; } - else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + { barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; } - else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { + else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) + { barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; } - else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + { barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; } - else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { + else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) + { barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; } - else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { + else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + { barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; sourceStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; } - else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { + else if (oldLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + { barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; sourceStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; destinationStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; } - else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { + else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + { barrier.srcAccessMask = 0; barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; destinationStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; } - else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) { + else if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) + { barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; barrier.dstAccessMask = 0; @@ -731,16 +781,16 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima destinationStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; } // we use general for images that are both sampled and compute write - else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_GENERAL) { + else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_GENERAL) + { barrier.srcAccessMask = 0; barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT; sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; destinationStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT; } - else { + else throw std::invalid_argument("unsupported layout transition!"); - } vkCmdPipelineBarrier( commandBuffer, diff --git a/src/modules/graphics/vulkan/Vulkan.h b/src/modules/graphics/vulkan/Vulkan.h index f0edb677b..a75925310 100644 --- a/src/modules/graphics/vulkan/Vulkan.h +++ b/src/modules/graphics/vulkan/Vulkan.h @@ -1,20 +1,25 @@ -#ifndef LOVE_GRAPHICS_VULKAN_VULKAN_H -#define LOVE_GRAPHICS_VULKAN_VULKAN_H +#pragma once #include "graphics/Graphics.h" #include "VulkanWrapper.h" -namespace love { -namespace graphics { -namespace vulkan { -enum InternalFormatRepresentation { +namespace love +{ +namespace graphics +{ +namespace vulkan +{ + +enum InternalFormatRepresentation +{ FORMATREPRESENTATION_FLOAT, FORMATREPRESENTATION_UINT, FORMATREPRESENTATION_SINT, FORMATREPRESENTATION_MAX_ENUM }; -struct TextureFormat { +struct TextureFormat +{ InternalFormatRepresentation internalFormatRepresentation; VkFormat internalFormat = VK_FORMAT_UNDEFINED; @@ -24,7 +29,8 @@ struct TextureFormat { VkComponentSwizzle swizzleA = VK_COMPONENT_SWIZZLE_IDENTITY; }; -class Vulkan { +class Vulkan +{ public: static void shaderSwitch(); static uint32_t getNumShaderSwitches(); @@ -59,8 +65,7 @@ public: VkCommandBuffer, VkImage, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t baseLevel = 0, uint32_t levelCount = 1, uint32_t baseLayer = 0, uint32_t layerCount = 1); }; + } // vulkan } // graphics } // love - -#endif diff --git a/src/modules/graphics/vulkan/VulkanWrapper.h b/src/modules/graphics/vulkan/VulkanWrapper.h index 6993bb66d..50bf1ee90 100644 --- a/src/modules/graphics/vulkan/VulkanWrapper.h +++ b/src/modules/graphics/vulkan/VulkanWrapper.h @@ -1,5 +1,4 @@ -#ifndef LOVE_GRAPHICS_VULKAN_VULKANWRAPPER_H -#define LOVE_GRAPHICS_VULKAN_VULKANWRAPPER_H +#pragma once #include "common/config.h" @@ -13,5 +12,3 @@ #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 #endif #include "vk_mem_alloc.h" - -#endif //LOVE_GRAPHICS_VULKAN_VULKANWRAPPER_H