mirror of
https://github.com/love2d/love.git
synced 2026-08-19 04:06:17 +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;
|
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) {
|
: love::graphics::Buffer(gfx, settings, format, size, arraylength), usageFlags(settings.usageFlags), allocator(allocator), gfx(gfx) {
|
||||||
loadVolatile();
|
loadVolatile();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace love {
|
|||||||
namespace vulkan {
|
namespace vulkan {
|
||||||
class Buffer : public love::graphics::Buffer, public Volatile {
|
class Buffer : public love::graphics::Buffer, public Volatile {
|
||||||
public:
|
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 ~Buffer();
|
||||||
|
|
||||||
virtual bool loadVolatile() override;
|
virtual bool loadVolatile() override;
|
||||||
|
|||||||
@@ -38,12 +38,14 @@ namespace love {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
const bool enableValidationLayers = false;
|
constexpr bool enableValidationLayers = false;
|
||||||
#else
|
#else
|
||||||
const bool enableValidationLayers = true;
|
constexpr bool enableValidationLayers = true;
|
||||||
#endif
|
#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 {
|
const char* Graphics::getName() const {
|
||||||
return "love.graphics.vulkan";
|
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) {
|
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(this, settings, format, data, size, arraylength);
|
||||||
return new Buffer(vmaAllocator, this, settings, format, data, size, arraylength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::present(void* screenshotCallbackdata) {
|
void Graphics::present(void* screenshotCallbackdata) {
|
||||||
@@ -135,8 +136,6 @@ namespace love {
|
|||||||
throw love::Exception("failed to present swap chain image");
|
throw love::Exception("failed to present swap chain image");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "present" << std::endl;
|
|
||||||
|
|
||||||
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
|
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
|
||||||
|
|
||||||
updatedBatchedDrawBuffers();
|
updatedBatchedDrawBuffers();
|
||||||
@@ -144,7 +143,6 @@ namespace love {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight) {
|
void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight) {
|
||||||
std::cout << "setViewPortSize ";
|
|
||||||
this->width = width;
|
this->width = width;
|
||||||
this->height = height;
|
this->height = height;
|
||||||
this->pixelWidth = pixelwidth;
|
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) {
|
bool Graphics::setMode(void* context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) {
|
||||||
std::cout << "setMode ";
|
|
||||||
|
|
||||||
createVulkanInstance();
|
createVulkanInstance();
|
||||||
createSurface();
|
createSurface();
|
||||||
pickPhysicalDevice();
|
pickPhysicalDevice();
|
||||||
@@ -166,10 +162,8 @@ namespace love {
|
|||||||
initCapabilities();
|
initCapabilities();
|
||||||
createSwapChain();
|
createSwapChain();
|
||||||
createImageViews();
|
createImageViews();
|
||||||
createRenderPass();
|
|
||||||
createDefaultShaders();
|
createDefaultShaders();
|
||||||
createDescriptorSetLayout();
|
createDescriptorSetLayout();
|
||||||
createFramebuffers();
|
|
||||||
createCommandPool();
|
createCommandPool();
|
||||||
createCommandBuffers();
|
createCommandBuffers();
|
||||||
createDefaultTexture();
|
createDefaultTexture();
|
||||||
@@ -211,8 +205,6 @@ namespace love {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::initCapabilities() {
|
void Graphics::initCapabilities() {
|
||||||
std::cout << "initCapabilities ";
|
|
||||||
|
|
||||||
// todo
|
// todo
|
||||||
capabilities.features[FEATURE_MULTI_RENDER_TARGET_FORMATS] = false;
|
capabilities.features[FEATURE_MULTI_RENDER_TARGET_FORMATS] = false;
|
||||||
capabilities.features[FEATURE_CLAMP_ZERO] = false;
|
capabilities.features[FEATURE_CLAMP_ZERO] = false;
|
||||||
@@ -258,8 +250,6 @@ namespace love {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::unSetMode() {
|
void Graphics::unSetMode() {
|
||||||
std::cout << "unSetMode ";
|
|
||||||
|
|
||||||
created = false;
|
created = false;
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
Volatile::unloadAll();
|
Volatile::unloadAll();
|
||||||
@@ -291,8 +281,6 @@ namespace love {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::setPointSize(float size) {
|
void Graphics::setPointSize(float size) {
|
||||||
std::cout << "setPointSize ";
|
|
||||||
|
|
||||||
if (size != states.back().pointSize)
|
if (size != states.back().pointSize)
|
||||||
flushBatchedDraws();
|
flushBatchedDraws();
|
||||||
|
|
||||||
@@ -300,8 +288,6 @@ namespace love {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Graphics::usesGLSLES() const {
|
bool Graphics::usesGLSLES() const {
|
||||||
std::cout << "usesGLSLES ";
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,16 +305,12 @@ namespace love {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::draw(const DrawCommand& cmd) {
|
void Graphics::draw(const DrawCommand& cmd) {
|
||||||
std::cout << "draw ";
|
|
||||||
|
|
||||||
prepareDraw(*cmd.attributes, *cmd.buffers, cmd.texture, cmd.primitiveType, cmd.cullMode);
|
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);
|
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) {
|
void Graphics::draw(const DrawIndexedCommand& cmd) {
|
||||||
std::cout << "drawIndexed ";
|
|
||||||
|
|
||||||
prepareDraw(*cmd.attributes, *cmd.buffers, cmd.texture, cmd.primitiveType, cmd.cullMode);
|
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));
|
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) {
|
void Graphics::setColor(Colorf c) {
|
||||||
std::cout << "setColor ";
|
|
||||||
|
|
||||||
c.r = std::min(std::max(c.r, 0.0f), 1.0f);
|
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.g = std::min(std::max(c.g, 0.0f), 1.0f);
|
||||||
c.b = std::min(std::max(c.b, 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) {
|
void Graphics::setWireframe(bool enable) {
|
||||||
std::cout << "setWireframe ";
|
|
||||||
|
|
||||||
flushBatchedDraws();
|
flushBatchedDraws();
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
@@ -362,8 +340,6 @@ namespace love {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const {
|
PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const {
|
||||||
std::cout << "getSizedFormat ";
|
|
||||||
|
|
||||||
switch (format) {
|
switch (format) {
|
||||||
PIXELFORMAT_NORMAL:
|
PIXELFORMAT_NORMAL:
|
||||||
if (isGammaCorrect()) {
|
if (isGammaCorrect()) {
|
||||||
@@ -380,20 +356,14 @@ namespace love {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) {
|
bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) {
|
||||||
std::cout << "isPixelFormatSupported ";
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer Graphics::getRenderer() const {
|
Renderer Graphics::getRenderer() const {
|
||||||
std::cout << "getRenderer ";
|
|
||||||
|
|
||||||
return RENDERER_VULKAN;
|
return RENDERER_VULKAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, graphics::Texture* texture) {
|
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_VERTICES_PER_DRAW = LOVE_UINT16_MAX;
|
||||||
const int MAX_QUADS_PER_DRAW = MAX_VERTICES_PER_DRAW / 4;
|
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) {
|
graphics::StreamBuffer* Graphics::newStreamBuffer(BufferUsage type, size_t size) {
|
||||||
std::cout << "newStreamBuffer ";
|
|
||||||
return new StreamBuffer(this, type, size);
|
return new StreamBuffer(this, type, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,6 +389,9 @@ namespace love {
|
|||||||
uint32 flags = DEVICE_PROJECTION_DEFAULT;
|
uint32 flags = DEVICE_PROJECTION_DEFAULT;
|
||||||
return calculateDeviceProjection(projection, flags);
|
return calculateDeviceProjection(projection, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Graphics::setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) {
|
||||||
|
}
|
||||||
|
|
||||||
// END IMPLEMENTATION OVERRIDDEN FUNCTIONS
|
// END IMPLEMENTATION OVERRIDDEN FUNCTIONS
|
||||||
|
|
||||||
@@ -444,29 +416,39 @@ namespace love {
|
|||||||
beginInfo.flags = 0;
|
beginInfo.flags = 0;
|
||||||
beginInfo.pInheritanceInfo = nullptr;
|
beginInfo.pInheritanceInfo = nullptr;
|
||||||
|
|
||||||
std::cout << "beginCommandBuffer(imageIndex=" << imageIndex << ") ";
|
|
||||||
if (vkBeginCommandBuffer(commandBuffers.at(imageIndex), &beginInfo) != VK_SUCCESS) {
|
if (vkBeginCommandBuffer(commandBuffers.at(imageIndex), &beginInfo) != VK_SUCCESS) {
|
||||||
throw love::Exception("failed to begin recording command buffer");
|
throw love::Exception("failed to begin recording command buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
VkRenderPassBeginInfo renderPassInfo{};
|
VkRenderingAttachmentInfo colorAttachmentInfo{};
|
||||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
colorAttachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
|
||||||
renderPassInfo.renderPass = renderPass;
|
colorAttachmentInfo.imageLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL;
|
||||||
renderPassInfo.framebuffer = swapChainFramBuffers.at(imageIndex);
|
colorAttachmentInfo.imageView = swapChainImageViews[imageIndex];
|
||||||
renderPassInfo.renderArea.offset = { 0, 0 };
|
colorAttachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
renderPassInfo.renderArea.extent = swapChainExtent;
|
colorAttachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
renderPassInfo.clearValueCount = 1;
|
colorAttachmentInfo.clearValue = clearColor;
|
||||||
renderPassInfo.pClearValues = &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;
|
currentGraphicsPipeline = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::endRecordingGraphicsCommands() {
|
void Graphics::endRecordingGraphicsCommands() {
|
||||||
const auto& commandBuffer = commandBuffers.at(imageIndex);
|
const auto& commandBuffer = commandBuffers.at(imageIndex);
|
||||||
|
|
||||||
std::cout << "endCommandBuffer(imageIndex=" << imageIndex << ") ";
|
vkCmdEndRendering(commandBuffer);
|
||||||
vkCmdEndRenderPass(commandBuffers.at(imageIndex));
|
|
||||||
|
Vulkan::cmdTransitionImageLayout(commandBuffer, swapChainImages[imageIndex], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||||
|
|
||||||
if (vkEndCommandBuffer(commandBuffers.at(imageIndex)) != VK_SUCCESS) {
|
if (vkEndCommandBuffer(commandBuffers.at(imageIndex)) != VK_SUCCESS) {
|
||||||
throw love::Exception("failed to record command buffer");
|
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.applicationVersion = VK_MAKE_VERSION(1, 0, 0); //todo, get this version from somewhere else?
|
||||||
appInfo.pEngineName = "LOVE Engine";
|
appInfo.pEngineName = "LOVE Engine";
|
||||||
appInfo.engineVersion = VK_MAKE_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_REV);
|
appInfo.engineVersion = VK_MAKE_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_REV);
|
||||||
appInfo.apiVersion = VK_API_VERSION_1_0;
|
appInfo.apiVersion = vulkanApiVersion;
|
||||||
|
|
||||||
VkInstanceCreateInfo createInfo{};
|
VkInstanceCreateInfo createInfo{};
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||||
@@ -809,6 +791,10 @@ namespace love {
|
|||||||
queueCreateInfos.push_back(queueCreateInfo);
|
queueCreateInfos.push_back(queueCreateInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkPhysicalDeviceDynamicRenderingFeatures dynamicRenderingFeature{};
|
||||||
|
dynamicRenderingFeature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES;
|
||||||
|
dynamicRenderingFeature.dynamicRendering = VK_TRUE;
|
||||||
|
|
||||||
VkPhysicalDeviceFeatures deviceFeatures{};
|
VkPhysicalDeviceFeatures deviceFeatures{};
|
||||||
deviceFeatures.samplerAnisotropy = VK_TRUE;
|
deviceFeatures.samplerAnisotropy = VK_TRUE;
|
||||||
|
|
||||||
@@ -817,7 +803,7 @@ namespace love {
|
|||||||
createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
|
createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
|
||||||
createInfo.pQueueCreateInfos = queueCreateInfos.data();
|
createInfo.pQueueCreateInfos = queueCreateInfos.data();
|
||||||
createInfo.pEnabledFeatures = &deviceFeatures;
|
createInfo.pEnabledFeatures = &deviceFeatures;
|
||||||
createInfo.pNext = nullptr;
|
createInfo.pNext = &dynamicRenderingFeature;
|
||||||
|
|
||||||
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
|
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
|
||||||
createInfo.ppEnabledExtensionNames = deviceExtensions.data();
|
createInfo.ppEnabledExtensionNames = deviceExtensions.data();
|
||||||
@@ -845,7 +831,7 @@ namespace love {
|
|||||||
vulkanFunctions.vkGetDeviceProcAddr = &vkGetDeviceProcAddr;
|
vulkanFunctions.vkGetDeviceProcAddr = &vkGetDeviceProcAddr;
|
||||||
|
|
||||||
VmaAllocatorCreateInfo allocatorCreateInfo = {};
|
VmaAllocatorCreateInfo allocatorCreateInfo = {};
|
||||||
allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_0;
|
allocatorCreateInfo.vulkanApiVersion = vulkanApiVersion;
|
||||||
allocatorCreateInfo.physicalDevice = physicalDevice;
|
allocatorCreateInfo.physicalDevice = physicalDevice;
|
||||||
allocatorCreateInfo.device = device;
|
allocatorCreateInfo.device = device;
|
||||||
allocatorCreateInfo.instance = instance;
|
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() {
|
void Graphics::createDefaultShaders() {
|
||||||
for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++) {
|
for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++) {
|
||||||
auto stype = (Shader::StandardShader)i;
|
auto stype = (Shader::StandardShader)i;
|
||||||
@@ -1379,6 +1323,11 @@ namespace love {
|
|||||||
}
|
}
|
||||||
graphicsPipelineLayouts.push_back(pipelineLayout);
|
graphicsPipelineLayouts.push_back(pipelineLayout);
|
||||||
|
|
||||||
|
VkPipelineRenderingCreateInfo pipelineRenderingCreateInfo{};
|
||||||
|
pipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
|
||||||
|
pipelineRenderingCreateInfo.colorAttachmentCount = 1;
|
||||||
|
pipelineRenderingCreateInfo.pColorAttachmentFormats = &swapChainImageFormat;
|
||||||
|
|
||||||
VkGraphicsPipelineCreateInfo pipelineInfo{};
|
VkGraphicsPipelineCreateInfo pipelineInfo{};
|
||||||
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||||
pipelineInfo.stageCount = static_cast<uint32_t>(shaderStages.size());
|
pipelineInfo.stageCount = static_cast<uint32_t>(shaderStages.size());
|
||||||
@@ -1392,10 +1341,10 @@ namespace love {
|
|||||||
pipelineInfo.pColorBlendState = &colorBlending;
|
pipelineInfo.pColorBlendState = &colorBlending;
|
||||||
pipelineInfo.pDynamicState = nullptr;
|
pipelineInfo.pDynamicState = nullptr;
|
||||||
pipelineInfo.layout = pipelineLayout;
|
pipelineInfo.layout = pipelineLayout;
|
||||||
pipelineInfo.renderPass = renderPass;
|
|
||||||
pipelineInfo.subpass = 0;
|
pipelineInfo.subpass = 0;
|
||||||
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
|
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
|
||||||
pipelineInfo.basePipelineIndex = -1;
|
pipelineInfo.basePipelineIndex = -1;
|
||||||
|
pipelineInfo.pNext = &pipelineRenderingCreateInfo;
|
||||||
|
|
||||||
VkPipeline graphicsPipeline;
|
VkPipeline graphicsPipeline;
|
||||||
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) {
|
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() {
|
void Graphics::createCommandPool() {
|
||||||
QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice);
|
QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice);
|
||||||
|
|
||||||
VkCommandPoolCreateInfo poolInfo{};
|
VkCommandPoolCreateInfo poolInfo{};
|
||||||
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value();
|
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) {
|
if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) {
|
||||||
throw love::Exception("failed to create command pool");
|
throw love::Exception("failed to create command pool");
|
||||||
@@ -1461,7 +1388,7 @@ namespace love {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::createCommandBuffers() {
|
void Graphics::createCommandBuffers() {
|
||||||
commandBuffers.resize(swapChainFramBuffers.size());
|
commandBuffers.resize(swapChainImages.size());
|
||||||
|
|
||||||
VkCommandBufferAllocateInfo allocInfo{};
|
VkCommandBufferAllocateInfo allocInfo{};
|
||||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
@@ -1591,12 +1518,7 @@ namespace love {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::cleanupSwapChain() {
|
void Graphics::cleanupSwapChain() {
|
||||||
std::cout << "cleanupSwapChain ";
|
|
||||||
|
|
||||||
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
|
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());
|
vkFreeCommandBuffers(device, commandPool, static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());
|
||||||
for (auto const& p : graphicsPipelines) {
|
for (auto const& p : graphicsPipelines) {
|
||||||
vkDestroyPipeline(device, p.second, nullptr);
|
vkDestroyPipeline(device, p.second, nullptr);
|
||||||
@@ -1607,7 +1529,6 @@ namespace love {
|
|||||||
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
||||||
}
|
}
|
||||||
graphicsPipelineLayouts.clear();
|
graphicsPipelineLayouts.clear();
|
||||||
vkDestroyRenderPass(device, renderPass, nullptr);
|
|
||||||
for (size_t i = 0; i < swapChainImageViews.size(); i++) {
|
for (size_t i = 0; i < swapChainImageViews.size(); i++) {
|
||||||
vkDestroyImageView(device, swapChainImageViews[i], nullptr);
|
vkDestroyImageView(device, swapChainImageViews[i], nullptr);
|
||||||
}
|
}
|
||||||
@@ -1626,8 +1547,6 @@ namespace love {
|
|||||||
|
|
||||||
createSwapChain();
|
createSwapChain();
|
||||||
createImageViews();
|
createImageViews();
|
||||||
createRenderPass();
|
|
||||||
createFramebuffers();
|
|
||||||
createDescriptorPool();
|
createDescriptorPool();
|
||||||
createCommandBuffers();
|
createCommandBuffers();
|
||||||
startRecordingGraphicsCommands();
|
startRecordingGraphicsCommands();
|
||||||
|
|||||||
@@ -85,22 +85,22 @@ namespace love {
|
|||||||
// implementation for virtual functions
|
// implementation for virtual functions
|
||||||
love::graphics::Texture* newTexture(const love::graphics::Texture::Settings& settings, const love::graphics::Texture::Slices* data = nullptr) override;
|
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;
|
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(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override { }
|
||||||
void clear(const std::vector<OptionalColorD>& colors, OptionalInt stencil, OptionalDouble depth) override { std::cout << "clear2 "; }
|
void clear(const std::vector<OptionalColorD>& colors, OptionalInt stencil, OptionalDouble depth) override { }
|
||||||
Matrix4 computeDeviceProjection(const Matrix4& projection, bool rendertotexture) const 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 present(void* screenshotCallbackdata) override;
|
||||||
void setViewportSize(int width, int height, int pixelwidth, int pixelheight) 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;
|
bool setMode(void* context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override;
|
||||||
void unSetMode() override;
|
void unSetMode() override;
|
||||||
void setActive(bool active) override { std::cout << "setActive "; }
|
void setActive(bool active) override { }
|
||||||
int getRequestedBackbufferMSAA() const override { std::cout << "getRequestedBackbufferMSAA "; return 0; }
|
int getRequestedBackbufferMSAA() const override { return 0; }
|
||||||
int getBackbufferMSAA() const override { std::cout << "getBackbufferMSAA "; return 0; }
|
int getBackbufferMSAA() const override { return 0; }
|
||||||
void setColor(Colorf c) override;
|
void setColor(Colorf c) override;
|
||||||
void setScissor(const Rect& rect) override { std::cout << "setScissor "; }
|
void setScissor(const Rect& rect) override { }
|
||||||
void setScissor() override { std::cout << "setScissor2 "; }
|
void setScissor() override { }
|
||||||
void setStencilMode(StencilAction action, CompareMode compare, int value, love::uint32 readmask, love::uint32 writemask) override { std::cout << "setStencilMode "; }
|
void setStencilMode(StencilAction action, CompareMode compare, int value, love::uint32 readmask, love::uint32 writemask) override { }
|
||||||
void setDepthMode(CompareMode compare, bool write) override { std::cout << "setDepthMode "; }
|
void setDepthMode(CompareMode compare, bool write) override { }
|
||||||
void setFrontFaceWinding(Winding winding) override;
|
void setFrontFaceWinding(Winding winding) override;
|
||||||
void setColorMask(ColorChannelMask mask) override;
|
void setColorMask(ColorChannelMask mask) override;
|
||||||
void setBlendState(const BlendState& blend) override;
|
void setBlendState(const BlendState& blend) override;
|
||||||
@@ -123,18 +123,16 @@ namespace love {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
graphics::ShaderStage* newShaderStageInternal(ShaderStageType stage, const std::string& cachekey, const std::string& source, bool gles) override {
|
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);
|
return new ShaderStage(this, stage, source, gles, cachekey);
|
||||||
}
|
}
|
||||||
graphics::Shader* newShaderInternal(StrongRef<love::graphics::ShaderStage> stages[SHADERSTAGE_MAX_ENUM]) override {
|
graphics::Shader* newShaderInternal(StrongRef<love::graphics::ShaderStage> stages[SHADERSTAGE_MAX_ENUM]) override {
|
||||||
std::cout << "newShaderInternal ";
|
|
||||||
return new Shader(stages);
|
return new Shader(stages);
|
||||||
}
|
}
|
||||||
graphics::StreamBuffer* newStreamBuffer(BufferUsage type, size_t size) override;
|
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 initCapabilities() override;
|
||||||
void getAPIStats(int& shaderswitches) const override { std::cout << "getAPIStats "; }
|
void getAPIStats(int& shaderswitches) const override { }
|
||||||
void setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) override { std::cout << "setRenderTargetsInternal "; }
|
void setRenderTargetsInternal(const RenderTargets& rts, int pixelw, int pixelh, bool hasSRGBtexture) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createVulkanInstance();
|
void createVulkanInstance();
|
||||||
@@ -152,13 +150,11 @@ namespace love {
|
|||||||
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities);
|
VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities);
|
||||||
void createSwapChain();
|
void createSwapChain();
|
||||||
void createImageViews();
|
void createImageViews();
|
||||||
void createRenderPass();
|
|
||||||
void createDefaultShaders();
|
void createDefaultShaders();
|
||||||
void createDescriptorSetLayout();
|
void createDescriptorSetLayout();
|
||||||
void createDescriptorPool();
|
void createDescriptorPool();
|
||||||
std::vector<VkDescriptorSet> createDescriptorSets(DecriptorSetConfiguration);
|
std::vector<VkDescriptorSet> createDescriptorSets(DecriptorSetConfiguration);
|
||||||
VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration);
|
VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration);
|
||||||
void createFramebuffers();
|
|
||||||
void createCommandPool();
|
void createCommandPool();
|
||||||
void createCommandBuffers();
|
void createCommandBuffers();
|
||||||
void createSyncObjects();
|
void createSyncObjects();
|
||||||
@@ -192,11 +188,9 @@ namespace love {
|
|||||||
std::vector<VkImageView> swapChainImageViews;
|
std::vector<VkImageView> swapChainImageViews;
|
||||||
VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
|
VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
|
||||||
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
||||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
|
||||||
VkPipeline currentGraphicsPipeline = 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<std::pair<GraphicsPipelineConfiguration, VkPipeline>> graphicsPipelines; // FIXME improve performance by using a hash map
|
||||||
std::vector<VkPipelineLayout> graphicsPipelineLayouts;
|
std::vector<VkPipelineLayout> graphicsPipelineLayouts;
|
||||||
std::vector<VkFramebuffer> swapChainFramBuffers;
|
|
||||||
VkCommandPool commandPool = VK_NULL_HANDLE;
|
VkCommandPool commandPool = VK_NULL_HANDLE;
|
||||||
std::vector<VkCommandBuffer> commandBuffers;
|
std::vector<VkCommandBuffer> commandBuffers;
|
||||||
VkClearValue clearColor = { {{0.0f, 0.0f, 0.0f, 1.0f}} };
|
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<graphics::Shader::BuiltinUniformData, graphics::StreamBuffer*>> uniformBufferMap;
|
||||||
std::vector<std::pair<DecriptorSetConfiguration, std::vector<VkDescriptorSet>>> descriptorSetsMap;
|
std::vector<std::pair<DecriptorSetConfiguration, std::vector<VkDescriptorSet>>> descriptorSetsMap;
|
||||||
VkPolygonMode currentPolygonMode = VK_POLYGON_MODE_FILL;
|
VkPolygonMode currentPolygonMode = VK_POLYGON_MODE_FILL;
|
||||||
|
|
||||||
|
VkCommandBuffer offscreenRendertargetCommandBuffer;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,11 +53,25 @@ namespace love {
|
|||||||
rect.h = sliceData->getHeight();
|
rect.h = sliceData->getHeight();
|
||||||
|
|
||||||
uploadByteData(format, dataPtr, size, 0, 0, rect);
|
uploadByteData(format, dataPtr, size, 0, 0, rect);
|
||||||
}
|
} else {
|
||||||
else {
|
if (isRenderTarget()) {
|
||||||
uint8 defaultPixel[] = { 255, 255, 255, 255 };
|
std::vector<uint8> defaultPixels;
|
||||||
Rect rect = { 0, 0, 1, 1 };
|
defaultPixels.reserve(width * height * 4);
|
||||||
uploadByteData(PIXELFORMAT_RGBA8_UNORM, defaultPixel, sizeof(defaultPixel), 0, 0, rect);
|
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();
|
createTextureImageView();
|
||||||
createTextureSampler();
|
createTextureSampler();
|
||||||
@@ -137,61 +151,7 @@ namespace love {
|
|||||||
void Texture::transitionImageLayout(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout) {
|
void Texture::transitionImageLayout(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout) {
|
||||||
auto commandBuffer = vgfx->beginSingleTimeCommands();
|
auto commandBuffer = vgfx->beginSingleTimeCommands();
|
||||||
|
|
||||||
VkPipelineStageFlags sourceStage;
|
Vulkan::cmdTransitionImageLayout(commandBuffer, image, oldLayout, newLayout);
|
||||||
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
|
|
||||||
);
|
|
||||||
|
|
||||||
vgfx->endSingleTimeCommands(commandBuffer);
|
vgfx->endSingleTimeCommands(commandBuffer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,18 +20,18 @@ namespace love {
|
|||||||
virtual bool loadVolatile() override;
|
virtual bool loadVolatile() override;
|
||||||
virtual void unloadVolatile() 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 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 { std::cout << "Texture::copyToBuffer "; };
|
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 getRenderTargetHandle() const override { return (ptrdiff_t)textureImage; };
|
||||||
ptrdiff_t getSamplerHandle() const override { std::cout << "Texture::getSamplerHandle "; return (ptrdiff_t)0; };
|
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 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; };
|
int getMSAA() const override { return 0; };
|
||||||
ptrdiff_t getHandle() const override { std::cout << "Texture::getHandle "; return (ptrdiff_t)textureImage; }
|
ptrdiff_t getHandle() const override { return (ptrdiff_t)textureImage; }
|
||||||
VkImageView getImageView() const { return textureImageView; }
|
VkImageView getImageView() const { return textureImageView; }
|
||||||
VkSampler getSampler() const { return textureSampler; }
|
VkSampler getSampler() const { return textureSampler; }
|
||||||
|
|
||||||
|
|||||||
@@ -398,6 +398,79 @@ namespace love {
|
|||||||
throw love::Exception("unknown cull mode");
|
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 VkColorComponentFlags getColorMask(ColorChannelMask);
|
||||||
static VkFrontFace getFrontFace(Winding);
|
static VkFrontFace getFrontFace(Winding);
|
||||||
static VkCullModeFlags getCullMode(CullMode);
|
static VkCullModeFlags getCullMode(CullMode);
|
||||||
|
|
||||||
|
static void cmdTransitionImageLayout(VkCommandBuffer, VkImage, VkImageLayout oldLayout, VkImageLayout newLayout);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user