diff --git a/src/common/Matrix.h b/src/common/Matrix.h index 77586b9bd..76e71dd1c 100644 --- a/src/common/Matrix.h +++ b/src/common/Matrix.h @@ -83,6 +83,16 @@ public: **/ void operator *= (const Matrix4 &m); + static friend bool operator==(const Matrix4& first, const Matrix4& other) + { + for (int i = 0; i < 16; i++) { + if (first.e[i] != other.e[i]) { + return false; + } + } + return true; + } + /** * Gets a pointer to the 16 array elements. * @return The array elements. diff --git a/src/modules/graphics/Shader.h b/src/modules/graphics/Shader.h index 669db3503..c8da04284 100644 --- a/src/modules/graphics/Shader.h +++ b/src/modules/graphics/Shader.h @@ -179,6 +179,14 @@ public: Vector4 normalMatrix[3]; // 3x3 matrix padded to an array of 3 vector4s. Vector4 screenSizeParams; Colorf constantColor; + + bool operator==(const BuiltinUniformData& other) { + auto first = *this; + return first.transformMatrix == other.transformMatrix && first.projectionMatrix == other.projectionMatrix + && first.normalMatrix[0] == other.normalMatrix[0] && first.normalMatrix[1] == other.normalMatrix[1] + && first.normalMatrix[2] == other.normalMatrix[2] && first.screenSizeParams == other.screenSizeParams + && first.constantColor == other.constantColor; + } }; // Pointer to currently active Shader. diff --git a/src/modules/graphics/vulkan/Buffer.cpp b/src/modules/graphics/vulkan/Buffer.cpp index 48e2f004b..a6090455d 100644 --- a/src/modules/graphics/vulkan/Buffer.cpp +++ b/src/modules/graphics/vulkan/Buffer.cpp @@ -32,7 +32,6 @@ namespace love { bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = size; bufferInfo.usage = getVulkanUsageFlags(settings.usageFlags); - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; VmaAllocationCreateInfo allocCreateInfo = {}; allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; @@ -57,6 +56,8 @@ namespace love { } 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) { diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 5c301fade..96079c4f2 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -121,8 +121,6 @@ namespace love { endRecordingGraphicsCommands(); - prepareDraw(currentFrame); - if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) { vkWaitForFences(device, 1, &imagesInFlight.at(imageIndex), VK_TRUE, UINT64_MAX); } @@ -209,7 +207,6 @@ namespace love { createFramebuffers(); createCommandPool(); createCommandBuffers(); - createUniformBuffers(); createDefaultTexture(); createQuadIndexBuffer(); createDescriptorPool(); @@ -333,12 +330,42 @@ namespace love { ensureGraphicsPipelineConfiguration(configuration); - vkCmdBindDescriptorSets(commandBuffers.at(imageIndex), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, getDescriptorSet(currentFrame), 0, nullptr); + auto descriptorSets = getDescriptorSet(currentFrame); + auto descriptorSet = *descriptorSets; + vkCmdBindDescriptorSets(commandBuffers.at(imageIndex), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, descriptorSets, 0, nullptr); vkCmdBindVertexBuffers(commandBuffers.at(imageIndex), 0, buffers.size(), buffers.data(), offsets.data()); vkCmdBindIndexBuffer(commandBuffers.at(imageIndex), (VkBuffer)cmd.indexBuffer->getHandle(), 0, getVulkanIndexBufferType(cmd.indexType)); vkCmdDrawIndexed(commandBuffers.at(imageIndex), static_cast(cmd.indexCount), 1, 0, 0, 0); } + PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const { + std::cout << "getSizedFormat "; + + switch (format) { + PIXELFORMAT_NORMAL: + if (isGammaCorrect()) { + return PIXELFORMAT_RGBA8_UNORM_sRGB; + } + else { + return PIXELFORMAT_RGBA8_UNORM; + } + case PIXELFORMAT_HDR: + return PIXELFORMAT_RGBA16_FLOAT; + default: + return format; + } + } + + bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) { + std::cout << "isPixelFormatSupported "; + switch (format) { + case PIXELFORMAT_LA8_UNORM: + return false; + default: + return true; + } + } + void Graphics::drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture) { std::cout << "drawQuads "; @@ -416,12 +443,29 @@ namespace love { } VkDescriptorSet* Graphics::getDescriptorSet(int currentFrame) { - auto it = textureToDescriptorSetsMap.find(currentTexture); - if (it == textureToDescriptorSetsMap.end()) { - textureToDescriptorSetsMap[currentTexture] = createDescriptorSets(currentTexture); + DecriptorSetConfiguration config; + config.texture = currentTexture; + config.buffer = getUniformBuffer(); + for (auto i = 0; i < descriptorSetsMap.size(); i++) { + if (descriptorSetsMap[i].first == config) { + return &descriptorSetsMap[i].second[currentFrame]; + } } + auto descriptorSets = createDescriptorSets(config); + descriptorSetsMap.push_back(std::make_pair(config, descriptorSets)); + return &descriptorSetsMap.back().second[currentFrame]; + } - return &textureToDescriptorSetsMap.at(currentTexture)[currentFrame]; + graphics::StreamBuffer* Graphics::getUniformBuffer() { + auto data = getCurrentBuiltinUniformData(); + for (auto it : uniformBufferMap) { + if (it.first == data) { + return it.second; + } + } + auto buffer = createUniformBufferFromData(data); + uniformBufferMap.push_back(std::make_pair(data, buffer)); + return buffer; } VkCommandBuffer Graphics::beginSingleTimeCommands() { @@ -456,9 +500,7 @@ namespace love { vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); } - void Graphics::prepareDraw(uint32_t currentImage) { - auto& buffer = uniformBuffers.at(currentImage); - + graphics::Shader::BuiltinUniformData Graphics::getCurrentBuiltinUniformData() { love::graphics::Shader::BuiltinUniformData data; data.transformMatrix = getTransform(); @@ -493,9 +535,16 @@ namespace love { data.constantColor = getColor(); gammaCorrectColor(data.constantColor); + return data; + } + + graphics::StreamBuffer* Graphics::createUniformBufferFromData(graphics::Shader::BuiltinUniformData data) { + auto buffer = newStreamBuffer(BUFFERUSAGE_UNIFORM, sizeof(data)); auto mappedInfo = buffer->map(0); memcpy(mappedInfo.data, &data, sizeof(data)); buffer->unmap(0); + + return buffer; } void Graphics::createVulkanInstance() { @@ -997,14 +1046,6 @@ namespace love { } } - void Graphics::createUniformBuffers() { - VkDeviceSize bufferSize = sizeof(graphics::Shader::BuiltinUniformData); - - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - uniformBuffers.push_back(std::make_unique(vmaAllocator, BUFFERUSAGE_UNIFORM, bufferSize)); - } - } - void Graphics::createDescriptorPool() { std::array poolSizes{}; poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; @@ -1026,7 +1067,7 @@ namespace love { } } - std::vector Graphics::createDescriptorSets(graphics::Texture* texture) { + std::vector Graphics::createDescriptorSets(DecriptorSetConfiguration config) { std::vector layouts(MAX_FRAMES_IN_FLIGHT, descriptorSetLayout); VkDescriptorSetAllocateInfo allocInfo{}; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; @@ -1055,13 +1096,13 @@ namespace love { for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { VkDescriptorBufferInfo bufferInfo{}; - bufferInfo.buffer = (VkBuffer)uniformBuffers.at(i)->getHandle(); + bufferInfo.buffer = (VkBuffer)config.buffer->getHandle(); bufferInfo.offset = 0; bufferInfo.range = sizeof(graphics::Shader::BuiltinUniformData); VkDescriptorImageInfo imageInfo{}; imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - Texture* vkTexture = (Texture*)texture; + Texture* vkTexture = (Texture*)config.texture; imageInfo.imageView = vkTexture->getImageView(); imageInfo.sampler = vkTexture->getSampler(); @@ -1448,8 +1489,8 @@ namespace love { vkDestroyImageView(device, swapChainImageViews[i], nullptr); } vkDestroySwapchainKHR(device, swapChain, nullptr); - uniformBuffers.clear(); - textureToDescriptorSetsMap.clear(); + uniformBufferMap.clear(); + descriptorSetsMap.clear(); } void Graphics::recreateSwapChain() { @@ -1461,7 +1502,6 @@ namespace love { createImageViews(); createRenderPass(); createFramebuffers(); - createUniformBuffers(); createDescriptorPool(); createCommandBuffers(); startRecordingGraphicsCommands(); diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index cb848171a..af6590b98 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -65,8 +65,8 @@ namespace love { void setBlendState(const BlendState& blend) override { std::cout << "setBlendState "; } void setPointSize(float size) override { std::cout << "setPointSize "; } void setWireframe(bool enable) override { std::cout << "setWireframe "; } - PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override { std::cout << "getSizedFormat "; return format; } - bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB = false) override { std::cout << "isPixelFormatSupported "; return true; } + PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override; + bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB = false) override; Renderer getRenderer() const override { std::cout << "getRenderer "; return RENDERER_VULKAN; } bool usesGLSLES() const override { std::cout << "usesGLSES "; return false; } RendererInfo getRendererInfo() const override { std::cout << "getRendererInfo "; return {}; } @@ -87,6 +87,15 @@ namespace love { friend static bool operator==(const GraphicsPipelineConfiguration& first, const GraphicsPipelineConfiguration& other); }; + struct DecriptorSetConfiguration { + graphics::Texture* texture; + graphics::StreamBuffer* buffer; + + bool operator==(const DecriptorSetConfiguration& conf2) { + return this->texture == conf2.texture && this->buffer == conf2.buffer; + } + }; + void setShader(Shader*); protected: @@ -112,8 +121,10 @@ namespace love { } VkDescriptorSet* getDescriptorSet(int currentFrame); + graphics::StreamBuffer* getUniformBuffer(); - std::unordered_map> textureToDescriptorSetsMap; + std::vector> uniformBufferMap; + std::vector>> descriptorSetsMap; struct BatchedDrawBuffers { StreamBuffer* vertexBuffer1; @@ -129,7 +140,7 @@ namespace love { } }; - // we need an arrow of draw buffers, since the frames are being rendered asynchronously + // we need an array of draw buffers, since the frames are being rendered asynchronously // and we can't (or shouldn't) update the contents of the buffers while they're still in flight / being rendered. std::vector batchedDrawBuffers; void updatedBatchedDrawBuffers(); @@ -173,9 +184,8 @@ namespace love { void createRenderPass(); void createDefaultShaders(); void createDescriptorSetLayout(); - void createUniformBuffers(); void createDescriptorPool(); - std::vector createDescriptorSets(graphics::Texture* texture); + std::vector createDescriptorSets(DecriptorSetConfiguration); VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration); void createFramebuffers(); void createCommandPool(); @@ -189,7 +199,8 @@ namespace love { void startRecordingGraphicsCommands(); void endRecordingGraphicsCommands(); void ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration); - void prepareDraw(uint32_t currentImage); + graphics::StreamBuffer* createUniformBufferFromData(graphics::Shader::BuiltinUniformData); + graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData(); VkInstance instance; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; @@ -211,7 +222,6 @@ namespace love { VkCommandPool commandPool; std::vector commandBuffers; VkClearValue clearColor = { {{0.0f, 0.0f, 0.0f, 1.0f}} }; - std::vector> uniformBuffers; VkDescriptorPool descriptorPool; std::vector imageAvailableSemaphores; std::vector renderFinishedSemaphores; diff --git a/src/modules/graphics/vulkan/StreamBuffer.h b/src/modules/graphics/vulkan/StreamBuffer.h index 1b981a8b0..4c3e79843 100644 --- a/src/modules/graphics/vulkan/StreamBuffer.h +++ b/src/modules/graphics/vulkan/StreamBuffer.h @@ -28,7 +28,6 @@ namespace love { VmaAllocator allocator; VmaAllocation allocation; VmaAllocationInfo allocInfo; - VkDevice device; VkBuffer buffer; size_t usedGPUMemory; diff --git a/src/modules/graphics/vulkan/Texture.cpp b/src/modules/graphics/vulkan/Texture.cpp index 354f84231..e5a97ed28 100644 --- a/src/modules/graphics/vulkan/Texture.cpp +++ b/src/modules/graphics/vulkan/Texture.cpp @@ -171,6 +171,8 @@ namespace love { } void Texture::uploadByteData(PixelFormat pixelformat, const void* data, size_t size, int level, int slice, const Rect& r) { + format = pixelformat; + VkBuffer stagingBuffer; VmaAllocation vmaAllocation; diff --git a/src/modules/graphics/vulkan/Texture.h b/src/modules/graphics/vulkan/Texture.h index c7541ec79..542a828bb 100644 --- a/src/modules/graphics/vulkan/Texture.h +++ b/src/modules/graphics/vulkan/Texture.h @@ -23,7 +23,7 @@ namespace love { ptrdiff_t getRenderTargetHandle() const override { std::cout << "Texture::getRenderTargetHandle "; return (ptrdiff_t)0; }; ptrdiff_t getSamplerHandle() const override { std::cout << "Texture::getSamplerHandle "; return (ptrdiff_t)0; }; - 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 { std::cout << "Texture::generateMipmapsInternal "; }; diff --git a/src/modules/graphics/vulkan/Vulkan.cpp b/src/modules/graphics/vulkan/Vulkan.cpp index 9d812b583..4f559f4af 100644 --- a/src/modules/graphics/vulkan/Vulkan.cpp +++ b/src/modules/graphics/vulkan/Vulkan.cpp @@ -163,12 +163,20 @@ namespace love { textureFormat.internalFormat = VK_FORMAT_R32G32_UINT; break; case PIXELFORMAT_RGBA8_UNORM: - case PIXELFORMAT_RGBA8_UNORM_sRGB: // fixme ? - textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_UNORM; + textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SRGB; // fixme? + break; + case PIXELFORMAT_RGBA8_UNORM_sRGB: + textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SRGB; break; case PIXELFORMAT_BGRA8_UNORM: - case PIXELFORMAT_BGRA8_UNORM_sRGB: // fixme ? - textureFormat.internalFormat = VK_FORMAT_B8G8R8A8_UNORM; + textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_UNORM; + textureFormat.swizzleR = VK_COMPONENT_SWIZZLE_B; + textureFormat.swizzleB = VK_COMPONENT_SWIZZLE_R; + break; + case PIXELFORMAT_BGRA8_UNORM_sRGB: + textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SRGB; + textureFormat.swizzleR = VK_COMPONENT_SWIZZLE_B; + textureFormat.swizzleB = VK_COMPONENT_SWIZZLE_R; break; case PIXELFORMAT_RGBA8_INT: textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SINT;