diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 9f8d8f46f..a98cc8140 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -149,8 +149,10 @@ Graphics *Graphics::createInstance() { for (auto r : rendererOrder) { +#ifdef LOVE_GRAPHICS_VULKAN // FIX ME: proper selection of vulkan backend instance = vulkan::createInstance(); +#endif if (std::find(_renderers.begin(), _renderers.end(), r) == _renderers.end()) continue; diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 1789ad17f..e881c239c 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -71,6 +71,7 @@ namespace love { createCommandPool(); createCommandBuffers(); createSyncObjects(); + startRecordingGraphicsCommands(); } } @@ -78,23 +79,68 @@ namespace love { cleanup(); } + // START OVERRIDEN FUNCTIONS + love::graphics::Buffer* Graphics::newBuffer(const love::graphics::Buffer::Settings& settings, const std::vector& format, const void* data, size_t size, size_t arraylength) { + std::cout << "newBuffer "; return nullptr; } - void Graphics::present(void* screenshotCallbackdata) { + void Graphics::startRecordingGraphicsCommands() { vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX); + + 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) { + throw love::Exception("failed to acquire swap chain image"); + } - uint32_t imageIndex; - VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); + break; + } - if (result == VK_ERROR_OUT_OF_DATE_KHR) { - recreateSwapChain(); - return; + VkCommandBufferBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = 0; + beginInfo.pInheritanceInfo = nullptr; + + std::cout << "beginCommandBuffer(imageIndex=" << imageIndex << ") "; + if (vkBeginCommandBuffer(commandBuffers.at(imageIndex), &beginInfo) != VK_SUCCESS) { + throw love::Exception("failed to begin recording command buffer"); } - else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { - throw love::Exception("failed to acquire swap chain image"); + + VkRenderPassBeginInfo renderPassInfo{}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = renderPass; + renderPassInfo.framebuffer = swapChainFramBuffers.at(imageIndex); + renderPassInfo.renderArea.offset = { 0, 0 }; + renderPassInfo.renderArea.extent = swapChainExtent; + renderPassInfo.clearValueCount = 1; + renderPassInfo.pClearValues = &clearColor; + + const auto& commandBuffer = commandBuffers.at(imageIndex); + + vkCmdBeginRenderPass(commandBuffers.at(imageIndex), &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + vkCmdBindPipeline(commandBuffers.at(imageIndex), VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline); + } + + void Graphics::endRecordingGraphicsCommands() { + const auto& commandBuffer = commandBuffers.at(imageIndex); + + std::cout << "endCommandBuffer(imageIndex=" << imageIndex << ") "; + vkCmdEndRenderPass(commandBuffers.at(imageIndex)); + if (vkEndCommandBuffer(commandBuffers.at(imageIndex)) != VK_SUCCESS) { + throw love::Exception("failed to record command buffer"); } + } + + void Graphics::present(void* screenshotCallbackdata) { + flushBatchedDraws(); + + endRecordingGraphicsCommands(); if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) { vkWaitForFences(device, 1, &imagesInFlight.at(imageIndex), VK_TRUE, UINT64_MAX); @@ -135,7 +181,7 @@ namespace love { presentInfo.pImageIndices = &imageIndex; - result = vkQueuePresentKHR(presentQueue, &presentInfo); + VkResult result = vkQueuePresentKHR(presentQueue, &presentInfo); if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) { framebufferResized = false; @@ -146,12 +192,52 @@ namespace love { } currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; + + std::cout << "present" << std::endl; + + startRecordingGraphicsCommands(); } void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight) { + std::cout << "setViewPortSize"; recreateSwapChain(); } + bool Graphics::setMode(void* context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) { + std::cout << "setMode "; + + if (batchedDrawState.vb[0] == nullptr) + { + // Initial sizes that should be good enough for most cases. It will + // resize to fit if needed, later. + batchedDrawState.vb[0] = new StreamBuffer(this, device, physicalDevice, BUFFERUSAGE_VERTEX, 1024 * 1024 * 1); + batchedDrawState.vb[1] = new StreamBuffer(this, device, physicalDevice, BUFFERUSAGE_VERTEX, 256 * 1024 * 1); + batchedDrawState.indexBuffer = new StreamBuffer(this, device, physicalDevice, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX); + } + + return true; + } + + void Graphics::draw(const DrawIndexedCommand& cmd) { + std::cout << "drawIndexed "; + + std::vector buffers; + std::vector offsets; + buffers.push_back((VkBuffer)cmd.buffers->info[0].buffer->getHandle()); + offsets.push_back((VkDeviceSize)cmd.buffers->info[0].offset); + buffers.push_back((VkBuffer)cmd.buffers->info[1].buffer->getHandle()); + offsets.push_back((VkDeviceSize)cmd.buffers->info[1].offset); + + vkCmdDraw(commandBuffers.at(imageIndex), 3, 1, 0, 0); // todo adjust + } + + graphics::StreamBuffer* Graphics::newStreamBuffer(BufferUsage type, size_t size) { + std::cout << "newStreamBuffer "; + return new StreamBuffer(this, device, physicalDevice, type, size); + } + + // END IMPLEMENTATION OVERRIDDEN FUNCTIONS + void Graphics::createVulkanInstance() { if (enableValidationLayers && !checkValidationSupport()) { throw love::Exception("validation layers requested, but not available"); @@ -626,11 +712,22 @@ namespace love { VkPipelineVertexInputStateCreateInfo vertexInputInfo{}; vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + VkVertexInputBindingDescription vertexBindingDescription; + vertexBindingDescription.binding = 0; + vertexBindingDescription.stride = 2 * sizeof(float); // just position for now + vertexBindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + // todo later + VkVertexInputAttributeDescription positionInputAttributeDescription; + positionInputAttributeDescription.binding = 0; + positionInputAttributeDescription.location = 0; + positionInputAttributeDescription.format = VK_FORMAT_R32G32_SFLOAT; + positionInputAttributeDescription.offset = 0; + vertexInputInfo.vertexBindingDescriptionCount = 0; - vertexInputInfo.pVertexBindingDescriptions = nullptr; + vertexInputInfo.pVertexBindingDescriptions = &vertexBindingDescription; vertexInputInfo.vertexAttributeDescriptionCount = 0; - vertexInputInfo.pVertexAttributeDescriptions = nullptr; + vertexInputInfo.pVertexAttributeDescriptions = &positionInputAttributeDescription; VkPipelineInputAssemblyStateCreateInfo inputAssembly{}; inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; @@ -777,38 +874,6 @@ namespace love { if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) { throw love::Exception("failed to allocate command buffers"); } - - for (size_t i = 0; i < commandBuffers.size(); i++) { - VkCommandBufferBeginInfo beginInfo{}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = 0; - beginInfo.pInheritanceInfo = nullptr; - - if (vkBeginCommandBuffer(commandBuffers[i], &beginInfo) != VK_SUCCESS) { - throw love::Exception("failed to begin recording command buffer"); - } - - VkRenderPassBeginInfo renderPassInfo{}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = renderPass; - renderPassInfo.framebuffer = swapChainFramBuffers.at(i); - renderPassInfo.renderArea.offset = { 0, 0 }; - renderPassInfo.renderArea.extent = swapChainExtent; - - VkClearValue clearColor = { {{0.0f, 0.0f, 0.0f, 1.0f}} }; - renderPassInfo.clearValueCount = 1; - renderPassInfo.pClearValues = &clearColor; - - // this definitely doesn't belong in here, but leaving here for future reference - vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline); - vkCmdDraw(commandBuffers[i], 3, 1, 0, 0); - - vkCmdEndRenderPass(commandBuffers[i]); - if (vkEndCommandBuffer(commandBuffers[i]) != VK_SUCCESS) { - throw love::Exception("failed to record command buffer"); - } - } } void Graphics::createSyncObjects() { @@ -834,6 +899,8 @@ namespace love { } void Graphics::cleanup() { + vkDeviceWaitIdle(device); + cleanupSwapChain(); for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { @@ -864,12 +931,15 @@ namespace love { void Graphics::recreateSwapChain() { vkDeviceWaitIdle(device); + cleanupSwapChain(); + createSwapChain(); createImageViews(); createRenderPass(); createGraphicsPipeline(); createFramebuffers(); createCommandBuffers(); + startRecordingGraphicsCommands(); } love::graphics::Graphics* createInstance() { diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 223b61eee..935c2171f 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -2,6 +2,7 @@ #define LOVE_GRAPHICS_VULKAN_GRAPHICS_H #include "graphics/Graphics.h" +#include "StreamBuffer.h" #include #include @@ -32,46 +33,46 @@ namespace love { } // implementation for virtual functions - Texture* newTexture(const Texture::Settings& settings, const Texture::Slices* data = nullptr) override { return nullptr; } + Texture* newTexture(const Texture::Settings& settings, const Texture::Slices* data = nullptr) override { std::cout << "newTexture"; return nullptr; } 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 { return Matrix4(); } - void discard(const std::vector& colorbuffers, bool depthstencil) override { } + void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override { std::cout << "clear1 "; } + void clear(const std::vector& colors, OptionalInt stencil, OptionalDouble depth) override { std::cout << "clear2 "; } + Matrix4 computeDeviceProjection(const Matrix4& projection, bool rendertotexture) const override { std::cout << "computeDeviceProjection "; return Matrix4(); } + void discard(const std::vector& colorbuffers, bool depthstencil) override { std::cout << "discard "; } 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 { return false; } - void unSetMode() override {} - void setActive(bool active) override {} - int getRequestedBackbufferMSAA() const override { return 0; } - int getBackbufferMSAA() const override { return 0; } - void setColor(Colorf c) 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 setPointSize(float size) override {} - void setWireframe(bool enable) override {} - PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override { return PIXELFORMAT_UNKNOWN; } - bool isPixelFormatSupported(PixelFormat format, PixelFormatUsageFlags usage, bool sRGB = false) override { return false; } - Renderer getRenderer() const override { return RENDERER_VULKAN; } - bool usesGLSLES() const override { return false; } - RendererInfo getRendererInfo() const override { return {}; } - void draw(const DrawCommand& cmd) override {} - void draw(const DrawIndexedCommand& cmd) override {} - void drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, Texture* texture) override {} + bool setMode(void* context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override; + void unSetMode() override { std::cout << "unSetMode "; } + void setActive(bool active) override { std::cout << "setActive "; } + int getRequestedBackbufferMSAA() const override { std::cout << "getRequestedBackbufferMSAA "; return 0; } + int getBackbufferMSAA() const override { std::cout << "getBackbufferMSAA "; return 0; } + void setColor(Colorf c) override { std::cout << "setColor "; } + void setScissor(const Rect& rect) override { std::cout << "setScissor "; } + void setScissor() override { std::cout << "setScissor2 "; } + void setStencilMode(StencilAction action, CompareMode compare, int value, love::uint32 readmask, love::uint32 writemask) override { std::cout << "setStencilMode "; } + void setDepthMode(CompareMode compare, bool write) override { std::cout << "setDepthMode "; } + void setFrontFaceWinding(Winding winding) override { std::cout << "setFrontFaceWinding "; } + void setColorMask(ColorChannelMask mask) override { std::cout << "setColorMask "; } + 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 PIXELFORMAT_UNKNOWN; } + bool isPixelFormatSupported(PixelFormat format, PixelFormatUsageFlags usage, bool sRGB = false) override { std::cout << "isPixelFormatSupported "; return false; } + 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 {}; } + void draw(const DrawCommand& cmd) override { std::cout << "draw "; } + void draw(const DrawIndexedCommand& cmd) override; + void drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, Texture* texture) override { std::cout << "drawQuads "; } protected: - ShaderStage* newShaderStageInternal(ShaderStageType stage, const std::string& cachekey, const std::string& source, bool gles) override { return nullptr; } - Shader* newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) override { return nullptr; } - StreamBuffer* newStreamBuffer(BufferUsage type, size_t size) override { return nullptr; } - bool dispatch(int x, int y, int z) override { return false; } - void initCapabilities() override {} - void getAPIStats(int& shaderswitches) const override {} - void setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) override {} + graphics::ShaderStage* newShaderStageInternal(ShaderStageType stage, const std::string& cachekey, const std::string& source, bool gles) override { std::cout << "newShaderStageInternal "; return nullptr; } + graphics::Shader* newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) override { std::cout << "newShaderInternal "; return nullptr; } + graphics::StreamBuffer* newStreamBuffer(BufferUsage type, size_t size) override; + bool dispatch(int x, int y, int z) override { std::cout << "dispatch "; return false; } + void initCapabilities() override { std::cout << "initCapabilities "; } + void getAPIStats(int& shaderswitches) const override { std::cout << "getAPIStats "; } + void setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) override { std::cout << "setRenderTargetsInternal "; } private: bool init = false; @@ -116,6 +117,9 @@ namespace love { void cleanupSwapChain(); void recreateSwapChain(); + void startRecordingGraphicsCommands(); + void endRecordingGraphicsCommands(); + VkInstance instance; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; VkDevice device; @@ -133,13 +137,17 @@ namespace love { std::vector swapChainFramBuffers; VkCommandPool commandPool; std::vector commandBuffers; + VkClearValue clearColor = { {{0.0f, 0.0f, 0.0f, 1.0f}} }; std::vector imageAvailableSemaphores; std::vector renderFinishedSemaphores; std::vector inFlightFences; std::vector imagesInFlight; size_t currentFrame = 0; + uint32_t imageIndex; bool framebufferResized = false; + + friend class StreamBuffer; }; } }