mirror of
https://github.com/love2d/love.git
synced 2026-08-14 01:20:56 +02:00
restructure to not hardcore draw vk commands
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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<love::graphics::Buffer::DataDeclaration>& 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<VkBuffer> buffers;
|
||||
std::vector<VkDeviceSize> 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() {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define LOVE_GRAPHICS_VULKAN_GRAPHICS_H
|
||||
|
||||
#include "graphics/Graphics.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include <common/config.h>
|
||||
@@ -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<love::graphics::Buffer::DataDeclaration>& 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<OptionalColorD>& colors, OptionalInt stencil, OptionalDouble depth) override {}
|
||||
Matrix4 computeDeviceProjection(const Matrix4& projection, bool rendertotexture) const override { return Matrix4(); }
|
||||
void discard(const std::vector<bool>& colorbuffers, bool depthstencil) override { }
|
||||
void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override { std::cout << "clear1 "; }
|
||||
void clear(const std::vector<OptionalColorD>& 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<bool>& 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<love::graphics::ShaderStage> 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<love::graphics::ShaderStage> 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<VkFramebuffer> swapChainFramBuffers;
|
||||
VkCommandPool commandPool;
|
||||
std::vector<VkCommandBuffer> commandBuffers;
|
||||
VkClearValue clearColor = { {{0.0f, 0.0f, 0.0f, 1.0f}} };
|
||||
|
||||
std::vector<VkSemaphore> imageAvailableSemaphores;
|
||||
std::vector<VkSemaphore> renderFinishedSemaphores;
|
||||
std::vector<VkFence> inFlightFences;
|
||||
std::vector<VkFence> imagesInFlight;
|
||||
size_t currentFrame = 0;
|
||||
uint32_t imageIndex;
|
||||
bool framebufferResized = false;
|
||||
|
||||
friend class StreamBuffer;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user