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:
niki
2022-07-14 18:01:46 +02:00
parent 38f15ae97d
commit 0ae81091d1
8 changed files with 165 additions and 215 deletions
+1 -1
View File
@@ -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();
}
+1 -1
View File
@@ -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;
+46 -127
View File
@@ -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();
+15 -19
View File
@@ -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;
};
}
}
+20 -60
View File
@@ -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);
}
+7 -7
View File
@@ -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; }
+73
View File
@@ -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
);
}
}
}
}
+2
View File
@@ -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);
};
}
}