mirror of
https://github.com/love2d/love.git
synced 2026-08-16 00:02:12 +02:00
vulkan: use dynamic rendering
This vulkan 1.3 feature will make the code simpler when dealing with off screen render targets (i.e. löve canvases)
This commit is contained in:
@@ -25,7 +25,7 @@ namespace love {
|
||||
return vkFlags;
|
||||
}
|
||||
|
||||
Buffer::Buffer(VmaAllocator allocator, love::graphics::Graphics* gfx, const Settings& settings, const std::vector<DataDeclaration>& format, const void* data, size_t size, size_t arraylength)
|
||||
Buffer::Buffer(love::graphics::Graphics* gfx, const Settings& settings, const std::vector<DataDeclaration>& format, const void* data, size_t size, size_t arraylength)
|
||||
: love::graphics::Buffer(gfx, settings, format, size, arraylength), usageFlags(settings.usageFlags), allocator(allocator), gfx(gfx) {
|
||||
loadVolatile();
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace love {
|
||||
namespace vulkan {
|
||||
class Buffer : public love::graphics::Buffer, public Volatile {
|
||||
public:
|
||||
Buffer(VmaAllocator allocator, love::graphics::Graphics* gfx, const Settings& settings, const std::vector<DataDeclaration>& format, const void* data, size_t size, size_t arraylength);
|
||||
Buffer(love::graphics::Graphics* gfx, const Settings& settings, const std::vector<DataDeclaration>& format, const void* data, size_t size, size_t arraylength);
|
||||
virtual ~Buffer();
|
||||
|
||||
virtual bool loadVolatile() override;
|
||||
|
||||
@@ -38,12 +38,14 @@ namespace love {
|
||||
};
|
||||
|
||||
#ifdef NDEBUG
|
||||
const bool enableValidationLayers = false;
|
||||
constexpr bool enableValidationLayers = false;
|
||||
#else
|
||||
const bool enableValidationLayers = true;
|
||||
constexpr bool enableValidationLayers = true;
|
||||
#endif
|
||||
|
||||
const int MAX_FRAMES_IN_FLIGHT = 2;
|
||||
constexpr int MAX_FRAMES_IN_FLIGHT = 2;
|
||||
|
||||
constexpr uint32_t vulkanApiVersion = VK_API_VERSION_1_3;
|
||||
|
||||
const char* Graphics::getName() const {
|
||||
return "love.graphics.vulkan";
|
||||
@@ -77,8 +79,7 @@ namespace love {
|
||||
}
|
||||
|
||||
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 new Buffer(vmaAllocator, this, settings, format, data, size, arraylength);
|
||||
return new Buffer(this, settings, format, data, size, arraylength);
|
||||
}
|
||||
|
||||
void Graphics::present(void* screenshotCallbackdata) {
|
||||
@@ -135,8 +136,6 @@ namespace love {
|
||||
throw love::Exception("failed to present swap chain image");
|
||||
}
|
||||
|
||||
std::cout << "present" << std::endl;
|
||||
|
||||
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
|
||||
|
||||
updatedBatchedDrawBuffers();
|
||||
@@ -144,7 +143,6 @@ namespace love {
|
||||
}
|
||||
|
||||
void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight) {
|
||||
std::cout << "setViewPortSize ";
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->pixelWidth = pixelwidth;
|
||||
@@ -156,8 +154,6 @@ namespace love {
|
||||
}
|
||||
|
||||
bool Graphics::setMode(void* context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) {
|
||||
std::cout << "setMode ";
|
||||
|
||||
createVulkanInstance();
|
||||
createSurface();
|
||||
pickPhysicalDevice();
|
||||
@@ -166,10 +162,8 @@ namespace love {
|
||||
initCapabilities();
|
||||
createSwapChain();
|
||||
createImageViews();
|
||||
createRenderPass();
|
||||
createDefaultShaders();
|
||||
createDescriptorSetLayout();
|
||||
createFramebuffers();
|
||||
createCommandPool();
|
||||
createCommandBuffers();
|
||||
createDefaultTexture();
|
||||
@@ -211,8 +205,6 @@ namespace love {
|
||||
}
|
||||
|
||||
void Graphics::initCapabilities() {
|
||||
std::cout << "initCapabilities ";
|
||||
|
||||
// todo
|
||||
capabilities.features[FEATURE_MULTI_RENDER_TARGET_FORMATS] = false;
|
||||
capabilities.features[FEATURE_CLAMP_ZERO] = false;
|
||||
@@ -258,8 +250,6 @@ namespace love {
|
||||
}
|
||||
|
||||
void Graphics::unSetMode() {
|
||||
std::cout << "unSetMode ";
|
||||
|
||||
created = false;
|
||||
vkDeviceWaitIdle(device);
|
||||
Volatile::unloadAll();
|
||||
@@ -291,8 +281,6 @@ namespace love {
|
||||
}
|
||||
|
||||
void Graphics::setPointSize(float size) {
|
||||
std::cout << "setPointSize ";
|
||||
|
||||
if (size != states.back().pointSize)
|
||||
flushBatchedDraws();
|
||||
|
||||
@@ -300,8 +288,6 @@ namespace love {
|
||||
}
|
||||
|
||||
bool Graphics::usesGLSLES() const {
|
||||
std::cout << "usesGLSLES ";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -319,16 +305,12 @@ namespace love {
|
||||
}
|
||||
|
||||
void Graphics::draw(const DrawCommand& cmd) {
|
||||
std::cout << "draw ";
|
||||
|
||||
prepareDraw(*cmd.attributes, *cmd.buffers, cmd.texture, cmd.primitiveType, cmd.cullMode);
|
||||
|
||||
vkCmdDraw(commandBuffers.at(imageIndex), static_cast<uint32_t>(cmd.vertexCount), static_cast<uint32_t>(cmd.instanceCount), static_cast<uint32_t>(cmd.vertexStart), 0);
|
||||
}
|
||||
|
||||
void Graphics::draw(const DrawIndexedCommand& cmd) {
|
||||
std::cout << "drawIndexed ";
|
||||
|
||||
prepareDraw(*cmd.attributes, *cmd.buffers, cmd.texture, cmd.primitiveType, cmd.cullMode);
|
||||
|
||||
vkCmdBindIndexBuffer(commandBuffers.at(imageIndex), (VkBuffer)cmd.indexBuffer->getHandle(), static_cast<VkDeviceSize>(cmd.indexBufferOffset), getVulkanIndexBufferType(cmd.indexType));
|
||||
@@ -336,8 +318,6 @@ namespace love {
|
||||
}
|
||||
|
||||
void Graphics::setColor(Colorf c) {
|
||||
std::cout << "setColor ";
|
||||
|
||||
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);
|
||||
@@ -347,8 +327,6 @@ namespace love {
|
||||
}
|
||||
|
||||
void Graphics::setWireframe(bool enable) {
|
||||
std::cout << "setWireframe ";
|
||||
|
||||
flushBatchedDraws();
|
||||
|
||||
if (enable) {
|
||||
@@ -362,8 +340,6 @@ namespace love {
|
||||
}
|
||||
|
||||
PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const {
|
||||
std::cout << "getSizedFormat ";
|
||||
|
||||
switch (format) {
|
||||
PIXELFORMAT_NORMAL:
|
||||
if (isGammaCorrect()) {
|
||||
@@ -380,20 +356,14 @@ namespace love {
|
||||
}
|
||||
|
||||
bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) {
|
||||
std::cout << "isPixelFormatSupported ";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Renderer Graphics::getRenderer() const {
|
||||
std::cout << "getRenderer ";
|
||||
|
||||
return RENDERER_VULKAN;
|
||||
}
|
||||
|
||||
void Graphics::drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture) {
|
||||
std::cout << "drawQuads ";
|
||||
|
||||
const int MAX_VERTICES_PER_DRAW = LOVE_UINT16_MAX;
|
||||
const int MAX_QUADS_PER_DRAW = MAX_VERTICES_PER_DRAW / 4;
|
||||
|
||||
@@ -412,7 +382,6 @@ namespace love {
|
||||
}
|
||||
|
||||
graphics::StreamBuffer* Graphics::newStreamBuffer(BufferUsage type, size_t size) {
|
||||
std::cout << "newStreamBuffer ";
|
||||
return new StreamBuffer(this, type, size);
|
||||
}
|
||||
|
||||
@@ -420,6 +389,9 @@ namespace love {
|
||||
uint32 flags = DEVICE_PROJECTION_DEFAULT;
|
||||
return calculateDeviceProjection(projection, flags);
|
||||
}
|
||||
|
||||
void Graphics::setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) {
|
||||
}
|
||||
|
||||
// END IMPLEMENTATION OVERRIDDEN FUNCTIONS
|
||||
|
||||
@@ -444,29 +416,39 @@ namespace love {
|
||||
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");
|
||||
}
|
||||
|
||||
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;
|
||||
VkRenderingAttachmentInfo colorAttachmentInfo{};
|
||||
colorAttachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
|
||||
colorAttachmentInfo.imageLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL;
|
||||
colorAttachmentInfo.imageView = swapChainImageViews[imageIndex];
|
||||
colorAttachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
colorAttachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
colorAttachmentInfo.clearValue = clearColor;
|
||||
|
||||
VkRenderingInfo renderingInfo{};
|
||||
renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO;
|
||||
renderingInfo.renderArea.extent = swapChainExtent;
|
||||
renderingInfo.layerCount = 1;
|
||||
renderingInfo.colorAttachmentCount = 1;
|
||||
renderingInfo.pColorAttachments = &colorAttachmentInfo;
|
||||
|
||||
Vulkan::cmdTransitionImageLayout(commandBuffers.at(imageIndex), swapChainImages[imageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
vkCmdBeginRendering(commandBuffers.at(imageIndex), &renderingInfo);
|
||||
|
||||
vkCmdBeginRenderPass(commandBuffers.at(imageIndex), &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
currentGraphicsPipeline = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void Graphics::endRecordingGraphicsCommands() {
|
||||
const auto& commandBuffer = commandBuffers.at(imageIndex);
|
||||
|
||||
std::cout << "endCommandBuffer(imageIndex=" << imageIndex << ") ";
|
||||
vkCmdEndRenderPass(commandBuffers.at(imageIndex));
|
||||
vkCmdEndRendering(commandBuffer);
|
||||
|
||||
Vulkan::cmdTransitionImageLayout(commandBuffer, swapChainImages[imageIndex], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
|
||||
if (vkEndCommandBuffer(commandBuffers.at(imageIndex)) != VK_SUCCESS) {
|
||||
throw love::Exception("failed to record command buffer");
|
||||
}
|
||||
@@ -601,7 +583,7 @@ namespace love {
|
||||
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); //todo, get this version from somewhere else?
|
||||
appInfo.pEngineName = "LOVE Engine";
|
||||
appInfo.engineVersion = VK_MAKE_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_REV);
|
||||
appInfo.apiVersion = VK_API_VERSION_1_0;
|
||||
appInfo.apiVersion = vulkanApiVersion;
|
||||
|
||||
VkInstanceCreateInfo createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
@@ -809,6 +791,10 @@ namespace love {
|
||||
queueCreateInfos.push_back(queueCreateInfo);
|
||||
}
|
||||
|
||||
VkPhysicalDeviceDynamicRenderingFeatures dynamicRenderingFeature{};
|
||||
dynamicRenderingFeature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES;
|
||||
dynamicRenderingFeature.dynamicRendering = VK_TRUE;
|
||||
|
||||
VkPhysicalDeviceFeatures deviceFeatures{};
|
||||
deviceFeatures.samplerAnisotropy = VK_TRUE;
|
||||
|
||||
@@ -817,7 +803,7 @@ namespace love {
|
||||
createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
|
||||
createInfo.pQueueCreateInfos = queueCreateInfos.data();
|
||||
createInfo.pEnabledFeatures = &deviceFeatures;
|
||||
createInfo.pNext = nullptr;
|
||||
createInfo.pNext = &dynamicRenderingFeature;
|
||||
|
||||
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
|
||||
createInfo.ppEnabledExtensionNames = deviceExtensions.data();
|
||||
@@ -845,7 +831,7 @@ namespace love {
|
||||
vulkanFunctions.vkGetDeviceProcAddr = &vkGetDeviceProcAddr;
|
||||
|
||||
VmaAllocatorCreateInfo allocatorCreateInfo = {};
|
||||
allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_0;
|
||||
allocatorCreateInfo.vulkanApiVersion = vulkanApiVersion;
|
||||
allocatorCreateInfo.physicalDevice = physicalDevice;
|
||||
allocatorCreateInfo.device = device;
|
||||
allocatorCreateInfo.instance = instance;
|
||||
@@ -1013,48 +999,6 @@ namespace love {
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::createRenderPass() {
|
||||
VkAttachmentDescription colorAttachment{};
|
||||
colorAttachment.format = swapChainImageFormat;
|
||||
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
|
||||
VkAttachmentReference colorAttachmentRef{};
|
||||
colorAttachmentRef.attachment = 0;
|
||||
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkSubpassDescription subpass{};
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpass.colorAttachmentCount = 1;
|
||||
subpass.pColorAttachments = &colorAttachmentRef;
|
||||
|
||||
VkSubpassDependency dependency{};
|
||||
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||
dependency.dstSubpass = 0;
|
||||
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependency.srcAccessMask = 0;
|
||||
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
|
||||
VkRenderPassCreateInfo renderPassInfo{};
|
||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
renderPassInfo.attachmentCount = 1;
|
||||
renderPassInfo.pAttachments = &colorAttachment;
|
||||
renderPassInfo.subpassCount = 1;
|
||||
renderPassInfo.pSubpasses = &subpass;
|
||||
renderPassInfo.dependencyCount = 1;
|
||||
renderPassInfo.pDependencies = &dependency;
|
||||
|
||||
if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
|
||||
throw love::Exception("failed to create render pass");
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::createDefaultShaders() {
|
||||
for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++) {
|
||||
auto stype = (Shader::StandardShader)i;
|
||||
@@ -1379,6 +1323,11 @@ namespace love {
|
||||
}
|
||||
graphicsPipelineLayouts.push_back(pipelineLayout);
|
||||
|
||||
VkPipelineRenderingCreateInfo pipelineRenderingCreateInfo{};
|
||||
pipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
|
||||
pipelineRenderingCreateInfo.colorAttachmentCount = 1;
|
||||
pipelineRenderingCreateInfo.pColorAttachmentFormats = &swapChainImageFormat;
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipelineInfo{};
|
||||
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
pipelineInfo.stageCount = static_cast<uint32_t>(shaderStages.size());
|
||||
@@ -1392,10 +1341,10 @@ namespace love {
|
||||
pipelineInfo.pColorBlendState = &colorBlending;
|
||||
pipelineInfo.pDynamicState = nullptr;
|
||||
pipelineInfo.layout = pipelineLayout;
|
||||
pipelineInfo.renderPass = renderPass;
|
||||
pipelineInfo.subpass = 0;
|
||||
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
|
||||
pipelineInfo.basePipelineIndex = -1;
|
||||
pipelineInfo.pNext = &pipelineRenderingCreateInfo;
|
||||
|
||||
VkPipeline graphicsPipeline;
|
||||
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) {
|
||||
@@ -1425,35 +1374,13 @@ namespace love {
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::createFramebuffers() {
|
||||
swapChainFramBuffers.resize(swapChainImageViews.size());
|
||||
for (size_t i = 0; i < swapChainImageViews.size(); i++) {
|
||||
VkImageView attachments[] = {
|
||||
swapChainImageViews.at(i)
|
||||
};
|
||||
|
||||
VkFramebufferCreateInfo framebufferInfo{};
|
||||
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
framebufferInfo.renderPass = renderPass;
|
||||
framebufferInfo.attachmentCount = 1;
|
||||
framebufferInfo.pAttachments = attachments;
|
||||
framebufferInfo.width = swapChainExtent.width;
|
||||
framebufferInfo.height = swapChainExtent.height;
|
||||
framebufferInfo.layers = 1;
|
||||
|
||||
if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramBuffers.at(i)) != VK_SUCCESS) {
|
||||
throw love::Exception("failed to create framebuffers");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::createCommandPool() {
|
||||
QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice);
|
||||
|
||||
VkCommandPoolCreateInfo poolInfo{};
|
||||
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value();
|
||||
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
|
||||
|
||||
if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) {
|
||||
throw love::Exception("failed to create command pool");
|
||||
@@ -1461,7 +1388,7 @@ namespace love {
|
||||
}
|
||||
|
||||
void Graphics::createCommandBuffers() {
|
||||
commandBuffers.resize(swapChainFramBuffers.size());
|
||||
commandBuffers.resize(swapChainImages.size());
|
||||
|
||||
VkCommandBufferAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
@@ -1591,12 +1518,7 @@ namespace love {
|
||||
}
|
||||
|
||||
void Graphics::cleanupSwapChain() {
|
||||
std::cout << "cleanupSwapChain ";
|
||||
|
||||
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
|
||||
for (size_t i = 0; i < swapChainFramBuffers.size(); i++) {
|
||||
vkDestroyFramebuffer(device, swapChainFramBuffers[i], nullptr);
|
||||
}
|
||||
vkFreeCommandBuffers(device, commandPool, static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());
|
||||
for (auto const& p : graphicsPipelines) {
|
||||
vkDestroyPipeline(device, p.second, nullptr);
|
||||
@@ -1607,7 +1529,6 @@ namespace love {
|
||||
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
||||
}
|
||||
graphicsPipelineLayouts.clear();
|
||||
vkDestroyRenderPass(device, renderPass, nullptr);
|
||||
for (size_t i = 0; i < swapChainImageViews.size(); i++) {
|
||||
vkDestroyImageView(device, swapChainImageViews[i], nullptr);
|
||||
}
|
||||
@@ -1626,8 +1547,6 @@ namespace love {
|
||||
|
||||
createSwapChain();
|
||||
createImageViews();
|
||||
createRenderPass();
|
||||
createFramebuffers();
|
||||
createDescriptorPool();
|
||||
createCommandBuffers();
|
||||
startRecordingGraphicsCommands();
|
||||
|
||||
@@ -85,22 +85,22 @@ namespace love {
|
||||
// implementation for virtual functions
|
||||
love::graphics::Texture* newTexture(const love::graphics::Texture::Settings& settings, const love::graphics::Texture::Slices* data = nullptr) override;
|
||||
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 { std::cout << "clear1 "; }
|
||||
void clear(const std::vector<OptionalColorD>& colors, OptionalInt stencil, OptionalDouble depth) override { std::cout << "clear2 "; }
|
||||
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;
|
||||
void discard(const std::vector<bool>& colorbuffers, bool depthstencil) override { std::cout << "discard "; }
|
||||
void discard(const std::vector<bool>& 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;
|
||||
void unSetMode() override;
|
||||
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 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 { 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 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;
|
||||
@@ -123,18 +123,16 @@ namespace love {
|
||||
|
||||
protected:
|
||||
graphics::ShaderStage* newShaderStageInternal(ShaderStageType stage, const std::string& cachekey, const std::string& source, bool gles) override {
|
||||
std::cout << "newShaderStageInternal ";
|
||||
return new ShaderStage(this, stage, source, gles, cachekey);
|
||||
}
|
||||
graphics::Shader* newShaderInternal(StrongRef<love::graphics::ShaderStage> stages[SHADERSTAGE_MAX_ENUM]) override {
|
||||
std::cout << "newShaderInternal ";
|
||||
return new Shader(stages);
|
||||
}
|
||||
graphics::StreamBuffer* newStreamBuffer(BufferUsage type, size_t size) override;
|
||||
bool dispatch(int x, int y, int z) override { std::cout << "dispatch "; return false; }
|
||||
bool dispatch(int x, int y, int z) override { return false; }
|
||||
void initCapabilities() override;
|
||||
void getAPIStats(int& shaderswitches) const override { std::cout << "getAPIStats "; }
|
||||
void setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) override { std::cout << "setRenderTargetsInternal "; }
|
||||
void getAPIStats(int& shaderswitches) const override { }
|
||||
void setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) override;
|
||||
|
||||
private:
|
||||
void createVulkanInstance();
|
||||
@@ -152,13 +150,11 @@ namespace love {
|
||||
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities);
|
||||
void createSwapChain();
|
||||
void createImageViews();
|
||||
void createRenderPass();
|
||||
void createDefaultShaders();
|
||||
void createDescriptorSetLayout();
|
||||
void createDescriptorPool();
|
||||
std::vector<VkDescriptorSet> createDescriptorSets(DecriptorSetConfiguration);
|
||||
VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration);
|
||||
void createFramebuffers();
|
||||
void createCommandPool();
|
||||
void createCommandBuffers();
|
||||
void createSyncObjects();
|
||||
@@ -192,11 +188,9 @@ namespace love {
|
||||
std::vector<VkImageView> swapChainImageViews;
|
||||
VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
|
||||
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||
VkPipeline currentGraphicsPipeline = VK_NULL_HANDLE;
|
||||
std::vector<std::pair<GraphicsPipelineConfiguration, VkPipeline>> graphicsPipelines; // FIXME improve performance by using a hash map
|
||||
std::vector<VkPipelineLayout> graphicsPipelineLayouts;
|
||||
std::vector<VkFramebuffer> swapChainFramBuffers;
|
||||
VkCommandPool commandPool = VK_NULL_HANDLE;
|
||||
std::vector<VkCommandBuffer> commandBuffers;
|
||||
VkClearValue clearColor = { {{0.0f, 0.0f, 0.0f, 1.0f}} };
|
||||
@@ -218,6 +212,8 @@ namespace love {
|
||||
std::vector<std::pair<graphics::Shader::BuiltinUniformData, graphics::StreamBuffer*>> uniformBufferMap;
|
||||
std::vector<std::pair<DecriptorSetConfiguration, std::vector<VkDescriptorSet>>> descriptorSetsMap;
|
||||
VkPolygonMode currentPolygonMode = VK_POLYGON_MODE_FILL;
|
||||
|
||||
VkCommandBuffer offscreenRendertargetCommandBuffer;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,11 +53,25 @@ namespace love {
|
||||
rect.h = sliceData->getHeight();
|
||||
|
||||
uploadByteData(format, dataPtr, size, 0, 0, rect);
|
||||
}
|
||||
else {
|
||||
uint8 defaultPixel[] = { 255, 255, 255, 255 };
|
||||
Rect rect = { 0, 0, 1, 1 };
|
||||
uploadByteData(PIXELFORMAT_RGBA8_UNORM, defaultPixel, sizeof(defaultPixel), 0, 0, rect);
|
||||
} else {
|
||||
if (isRenderTarget()) {
|
||||
std::vector<uint8> defaultPixels;
|
||||
defaultPixels.reserve(width * height * 4);
|
||||
for (size_t i = 0; i < width * height; i++) {
|
||||
// transparent white
|
||||
defaultPixels.push_back(255);
|
||||
defaultPixels.push_back(255);
|
||||
defaultPixels.push_back(255);
|
||||
defaultPixels.push_back(0);
|
||||
}
|
||||
Rect rect = { 0, 0, width, height };
|
||||
uploadByteData(PIXELFORMAT_RGBA8_UNORM, defaultPixels.data(), defaultPixels.size(), 0, 0, rect);
|
||||
}
|
||||
else {
|
||||
std::vector<uint8> defaultPixels(width * height * 4, 255);
|
||||
Rect rect = { 0, 0, width, height };
|
||||
uploadByteData(PIXELFORMAT_RGBA8_UNORM, defaultPixels.data(), defaultPixels.size(), 0, 0, rect);
|
||||
}
|
||||
}
|
||||
createTextureImageView();
|
||||
createTextureSampler();
|
||||
@@ -137,61 +151,7 @@ namespace love {
|
||||
void Texture::transitionImageLayout(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout) {
|
||||
auto commandBuffer = vgfx->beginSingleTimeCommands();
|
||||
|
||||
VkPipelineStageFlags sourceStage;
|
||||
VkPipelineStageFlags destinationStage;
|
||||
|
||||
VkImageMemoryBarrier barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.oldLayout = oldLayout;
|
||||
barrier.newLayout = newLayout;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = image;
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
barrier.subresourceRange.baseMipLevel = 0;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
|
||||
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
||||
barrier.srcAccessMask = 0;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
} 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_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_GENERAL) {
|
||||
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_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_GENERAL) {
|
||||
barrier.srcAccessMask = 0;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
}
|
||||
else {
|
||||
throw love::Exception("unsupported lay transition");
|
||||
}
|
||||
|
||||
vkCmdPipelineBarrier(
|
||||
commandBuffer,
|
||||
sourceStage, destinationStage,
|
||||
0,
|
||||
0, nullptr,
|
||||
0, nullptr,
|
||||
1, &barrier
|
||||
);
|
||||
Vulkan::cmdTransitionImageLayout(commandBuffer, image, oldLayout, newLayout);
|
||||
|
||||
vgfx->endSingleTimeCommands(commandBuffer);
|
||||
}
|
||||
|
||||
@@ -20,18 +20,18 @@ namespace love {
|
||||
virtual bool loadVolatile() override;
|
||||
virtual void unloadVolatile() override;
|
||||
|
||||
void copyFromBuffer(graphics::Buffer* source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect& rect) override { std::cout << "Texture::copyFromBuffer "; };
|
||||
void copyToBuffer(graphics::Buffer* dest, int slice, int mipmap, const Rect& rect, size_t destoffset, int destwidth, size_t size) override { std::cout << "Texture::copyToBuffer "; };
|
||||
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 { std::cout << "Texture::getRenderTargetHandle "; return (ptrdiff_t)0; };
|
||||
ptrdiff_t getSamplerHandle() const override { std::cout << "Texture::getSamplerHandle "; return (ptrdiff_t)0; };
|
||||
ptrdiff_t getRenderTargetHandle() const override { return (ptrdiff_t)textureImage; };
|
||||
ptrdiff_t getSamplerHandle() const override { return (ptrdiff_t)textureSampler; };
|
||||
|
||||
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 "; };
|
||||
void generateMipmapsInternal() override { };
|
||||
|
||||
int getMSAA() const override { std::cout << "Texture::getMSAA "; return 0; };
|
||||
ptrdiff_t getHandle() const override { std::cout << "Texture::getHandle "; return (ptrdiff_t)textureImage; }
|
||||
int getMSAA() const override { return 0; };
|
||||
ptrdiff_t getHandle() const override { return (ptrdiff_t)textureImage; }
|
||||
VkImageView getImageView() const { return textureImageView; }
|
||||
VkSampler getSampler() const { return textureSampler; }
|
||||
|
||||
|
||||
@@ -398,6 +398,79 @@ namespace love {
|
||||
throw love::Exception("unknown cull mode");
|
||||
}
|
||||
}
|
||||
|
||||
void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout) {
|
||||
VkImageMemoryBarrier barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.oldLayout = oldLayout;
|
||||
barrier.newLayout = newLayout;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = image;
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
barrier.subresourceRange.baseMipLevel = 0;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
|
||||
VkPipelineStageFlags sourceStage;
|
||||
VkPipelineStageFlags destinationStage;
|
||||
|
||||
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
||||
barrier.srcAccessMask = 0;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
}
|
||||
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_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_GENERAL) {
|
||||
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_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_GENERAL) {
|
||||
barrier.srcAccessMask = 0;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
}
|
||||
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_BOTTOM_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) {
|
||||
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
barrier.dstAccessMask = 0;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
||||
}
|
||||
else {
|
||||
throw std::invalid_argument("unsupported layout transition!");
|
||||
}
|
||||
|
||||
vkCmdPipelineBarrier(
|
||||
commandBuffer,
|
||||
sourceStage, destinationStage,
|
||||
0,
|
||||
0, nullptr,
|
||||
0, nullptr,
|
||||
1, &barrier
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace love {
|
||||
static VkColorComponentFlags getColorMask(ColorChannelMask);
|
||||
static VkFrontFace getFrontFace(Winding);
|
||||
static VkCullModeFlags getCullMode(CullMode);
|
||||
|
||||
static void cmdTransitionImageLayout(VkCommandBuffer, VkImage, VkImageLayout oldLayout, VkImageLayout newLayout);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user