vulkan: implement MSAA textures.

This commit is contained in:
Sasha Szpakowski
2024-12-01 14:23:13 -04:00
parent 2e58f1db5c
commit fe4fc84659
7 changed files with 345 additions and 210 deletions
+104 -63
View File
@@ -326,7 +326,7 @@ void Graphics::submitGpuCommands(SubmitMode submitMode, void *screenshotCallback
if (submitMode == SUBMIT_PRESENT)
{
VkImage backbufferImage = fakeBackbuffer != nullptr ? (VkImage)fakeBackbuffer->getHandle() : swapChainImages.at(imageIndex);
VkImage backbufferImage = fakeBackbuffer != nullptr ? (VkImage)fakeBackbuffer->getRenderTargetHandle() : swapChainImages.at(imageIndex);
if (pendingScreenshotCallbacks.empty())
{
@@ -1193,13 +1193,8 @@ static bool computeDispatchBarrierFlags(Shader *shader, VkAccessFlags &dstAccess
// All writable images use the GENERAL layout.
// TODO: this is pretty messy.
VkAccessFlags texAccessFlags = 0;
VkPipelineStageFlags texStageFlags = 0;
bool depthStencil = isPixelFormatDepthStencil(tex->getPixelFormat());
Vulkan::setImageLayoutTransitionOptions(false, tex->isRenderTarget(), depthStencil, VK_IMAGE_LAYOUT_GENERAL, texAccessFlags, texStageFlags);
dstAccessFlags |= texAccessFlags;
dstStageFlags |= texStageFlags;
Vulkan::addImageLayoutTransitionOptions(false, tex->isRenderTarget(), depthStencil, VK_IMAGE_LAYOUT_GENERAL, dstAccessFlags, dstStageFlags);
}
for (const auto &info : shader->getActiveStorageBufferInfo())
@@ -1285,7 +1280,7 @@ void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int pixelw, in
if (isWindow)
setDefaultRenderPass();
else
setRenderPass(rts, pixelw, pixelh, hasSRGBtexture);
setRenderPass(rts, pixelw, pixelh);
}
// END IMPLEMENTATION OVERRIDDEN FUNCTIONS
@@ -2120,8 +2115,9 @@ VkFramebuffer Graphics::createFramebuffer(FramebufferConfiguration &configuratio
if (configuration.staticData.depthView)
attachments.push_back(configuration.staticData.depthView);
if (configuration.staticData.resolveView)
attachments.push_back(configuration.staticData.resolveView);
// Resolve attachments after everything else to match createRenderPass.
for (const auto &colorResolveView : configuration.colorResolveViews)
attachments.push_back(colorResolveView);
VkFramebufferCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
@@ -2198,6 +2194,7 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration)
std::vector<VkAttachmentDescription> attachments;
std::vector<VkAttachmentReference> colorAttachmentRefs;
std::vector<VkAttachmentReference> colorResolveAttachmentRefs;
uint32_t attachment = 0;
for (const auto &colorAttachment : configuration.colorAttachments)
@@ -2214,24 +2211,33 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration)
colorDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorDescription.initialLayout = colorAttachment.layout;
colorDescription.finalLayout = colorAttachment.layout;
if (colorAttachment.msaaSamples > 1)
{
colorDescription.initialLayout = colorAttachment.msaaLayout;
colorDescription.finalLayout = colorAttachment.msaaLayout;
}
else
{
colorDescription.initialLayout = colorAttachment.layout;
colorDescription.finalLayout = colorAttachment.layout;
}
attachments.push_back(colorDescription);
VkAccessFlags texBeginAccessFlags = 0;
VkPipelineStageFlags texBeginStageFlags = 0;
Vulkan::setImageLayoutTransitionOptions(true, true, false, colorAttachment.layout, texBeginAccessFlags, texBeginStageFlags);
beginDependency.srcAccessMask |= texBeginAccessFlags;
beginDependency.srcStageMask |= texBeginStageFlags;
// I had a TODO here, but I don't remember why...
if (colorAttachment.layout != VK_IMAGE_LAYOUT_UNDEFINED)
{
Vulkan::addImageLayoutTransitionOptions(true, true, false, colorAttachment.layout, beginDependency.srcAccessMask, beginDependency.srcStageMask);
Vulkan::addImageLayoutTransitionOptions(false, true, false, colorAttachment.layout, endDependency.dstAccessMask, endDependency.dstStageMask);
}
VkAccessFlags texEndAccessFlags = 0;
VkPipelineStageFlags texEndStageFlags = 0;
Vulkan::setImageLayoutTransitionOptions(false, true, false, colorAttachment.layout, texEndAccessFlags, texEndStageFlags);
endDependency.dstAccessMask |= texEndAccessFlags;
endDependency.dstStageMask |= texEndStageFlags;
if (colorAttachment.msaaLayout != VK_IMAGE_LAYOUT_UNDEFINED)
{
Vulkan::addImageLayoutTransitionOptions(true, true, false, colorAttachment.msaaLayout, beginDependency.srcAccessMask, beginDependency.srcStageMask);
Vulkan::addImageLayoutTransitionOptions(false, true, false, colorAttachment.msaaLayout, endDependency.dstAccessMask, endDependency.dstStageMask);
}
}
subPass.colorAttachmentCount = static_cast<uint32_t>(colorAttachmentRefs.size());
subPass.colorAttachmentCount = static_cast<uint32_t>(configuration.colorAttachments.size());
subPass.pColorAttachments = colorAttachmentRefs.data();
VkAttachmentReference depthStencilAttachmentRef{};
@@ -2252,36 +2258,43 @@ VkRenderPass Graphics::createRenderPass(RenderPassConfiguration &configuration)
depthStencilAttachment.finalLayout = configuration.staticData.depthStencilAttachment.layout;
attachments.push_back(depthStencilAttachment);
VkAccessFlags texBeginAccessFlags = 0;
VkPipelineStageFlags texBeginStageFlags = 0;
Vulkan::setImageLayoutTransitionOptions(true, true, true, configuration.staticData.depthStencilAttachment.layout, texBeginAccessFlags, texBeginStageFlags);
beginDependency.srcAccessMask |= texBeginAccessFlags;
beginDependency.srcStageMask |= texBeginStageFlags;
VkAccessFlags texEndAccessFlags = 0;
VkPipelineStageFlags texEndStageFlags = 0;
Vulkan::setImageLayoutTransitionOptions(false, true, true, configuration.staticData.depthStencilAttachment.layout, texEndAccessFlags, texEndStageFlags);
endDependency.dstAccessMask |= texEndAccessFlags;
endDependency.dstStageMask |= texEndStageFlags;
Vulkan::addImageLayoutTransitionOptions(true, true, true, configuration.staticData.depthStencilAttachment.layout, beginDependency.srcAccessMask, beginDependency.srcStageMask);
Vulkan::addImageLayoutTransitionOptions(false, true, true, configuration.staticData.depthStencilAttachment.layout, endDependency.dstAccessMask, endDependency.dstStageMask);
}
VkAttachmentReference colorAttachmentResolveRef{};
// Add resolve attachments after everything else to make pClearValues simpler to implement.
if (configuration.staticData.resolve)
{
colorAttachmentResolveRef.attachment = attachment++;
colorAttachmentResolveRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
subPass.pResolveAttachments = &colorAttachmentResolveRef;
for (const auto &colorAttachment : configuration.colorAttachments)
{
VkAttachmentReference reference{};
reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentDescription colorAttachmentResolve{};
colorAttachmentResolve.format = configuration.colorAttachments.at(0).format;
colorAttachmentResolve.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachmentResolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachmentResolve.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachmentResolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachmentResolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachmentResolve.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments.push_back(colorAttachmentResolve);
if (colorAttachment.layout == VK_IMAGE_LAYOUT_UNDEFINED)
{
reference.attachment = VK_ATTACHMENT_UNUSED;
colorResolveAttachmentRefs.push_back(reference);
}
else
{
reference.attachment = attachment++;
colorResolveAttachmentRefs.push_back(reference);
VkAttachmentDescription resolveDescription{};
resolveDescription.format = colorAttachment.format;
resolveDescription.samples = VK_SAMPLE_COUNT_1_BIT;
resolveDescription.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
resolveDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
resolveDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
resolveDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
resolveDescription.initialLayout = colorAttachment.layout;
resolveDescription.finalLayout = colorAttachment.layout;
attachments.push_back(resolveDescription);
}
}
subPass.pResolveAttachments = colorResolveAttachmentRefs.data();
}
std::array<VkSubpassDependency, 2> dependencies = { beginDependency, endDependency };
@@ -2496,8 +2509,6 @@ void Graphics::setDefaultRenderPass()
RenderPassConfiguration renderPassConfiguration{};
renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples });
VkFormat dsformat = backbufferHasDepth || backbufferHasStencil ? depthStencilFormat : VK_FORMAT_UNDEFINED;
renderPassConfiguration.staticData.depthStencilAttachment = { dsformat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples };
if (msaaSamples & VK_SAMPLE_COUNT_1_BIT)
@@ -2512,19 +2523,22 @@ void Graphics::setDefaultRenderPass()
if (msaaSamples & VK_SAMPLE_COUNT_1_BIT)
{
renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples });
if (!swapChainImageViews.empty())
framebufferConfiguration.colorViews.push_back(swapChainImageViews.at(imageIndex));
else
framebufferConfiguration.colorViews.push_back(fakeBackbuffer->getRenderTargetView(0, 0));
framebufferConfiguration.staticData.resolveView = VK_NULL_HANDLE;
}
else
{
renderPassConfiguration.colorAttachments.push_back({ swapChainImageFormat, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ATTACHMENT_LOAD_OP_LOAD, msaaSamples });
framebufferConfiguration.colorViews.push_back(colorImageView);
if (!swapChainImageViews.empty())
framebufferConfiguration.staticData.resolveView = swapChainImageViews.at(imageIndex);
framebufferConfiguration.colorResolveViews.push_back(swapChainImageViews.at(imageIndex));
else
framebufferConfiguration.staticData.resolveView = fakeBackbuffer->getRenderTargetView(0, 0);
framebufferConfiguration.colorResolveViews.push_back(fakeBackbuffer->getRenderTargetView(0, 0));
}
renderPassState.renderPassConfiguration = std::move(renderPassConfiguration);
@@ -2554,35 +2568,62 @@ void Graphics::setDefaultRenderPass()
}
}
void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture)
void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh)
{
// fixme: hasSRGBtexture
RenderPassConfiguration renderPassConfiguration{};
VkSampleCountFlagBits msaa = VK_SAMPLE_COUNT_1_BIT;
for (const auto &color : rts.colors)
{
auto tex = (Texture *)color.texture;
renderPassConfiguration.colorAttachments.push_back({
Vulkan::getTextureFormat(color.texture->getPixelFormat()).internalFormat,
((Texture*)color.texture)->getImageLayout(),
Vulkan::getTextureFormat(tex->getPixelFormat()).internalFormat,
tex->getImageLayout(),
tex->getMSAAImageLayout(),
VK_ATTACHMENT_LOAD_OP_LOAD,
dynamic_cast<Texture*>(color.texture)->getMsaaSamples() });
tex->getMsaaSamples() });
if (tex->getMSAAImageLayout() != VK_IMAGE_LAYOUT_UNDEFINED && tex->getImageLayout() != VK_IMAGE_LAYOUT_UNDEFINED)
renderPassConfiguration.staticData.resolve = true;
msaa = tex->getMsaaSamples();
}
if (rts.depthStencil.texture != nullptr)
{
auto tex = (Texture *)rts.depthStencil.texture;
renderPassConfiguration.staticData.depthStencilAttachment = {
Vulkan::getTextureFormat(rts.depthStencil.texture->getPixelFormat()).internalFormat,
((Texture*)rts.depthStencil.texture)->getImageLayout(),
tex->getImageLayout(),
VK_ATTACHMENT_LOAD_OP_LOAD,
VK_ATTACHMENT_LOAD_OP_LOAD,
dynamic_cast<Texture*>(rts.depthStencil.texture)->getMsaaSamples() };
tex->getMsaaSamples() };
msaa = tex->getMsaaSamples();
}
FramebufferConfiguration configuration{};
for (const auto &color : rts.colors)
{
auto tex = (Texture*)color.texture;
configuration.colorViews.push_back(tex->getRenderTargetView(color.mipmap, color.slice));
if (tex->getMSAA() > 1)
{
configuration.colorViews.push_back(tex->getMSAARenderTargetView(color.mipmap, color.slice));
configuration.colorResolveViews.push_back(tex->getRenderTargetView(color.mipmap, color.slice));
}
else
{
configuration.colorViews.push_back(tex->getRenderTargetView(color.mipmap, color.slice));
}
}
if (rts.depthStencil.texture != nullptr)
{
auto tex = (Texture*)rts.depthStencil.texture;
configuration.staticData.depthView = tex->getRenderTargetView(rts.depthStencil.mipmap, rts.depthStencil.slice);
if (tex->getMSAA() > 1)
configuration.staticData.depthView = tex->getMSAARenderTargetView(rts.depthStencil.mipmap, rts.depthStencil.slice);
else
configuration.staticData.depthView = tex->getRenderTargetView(rts.depthStencil.mipmap, rts.depthStencil.slice);
}
configuration.staticData.width = static_cast<uint32_t>(pixelw);
@@ -2606,7 +2647,7 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b
renderPassState.pipeline = VK_NULL_HANDLE;
renderPassState.width = static_cast<float>(pixelw);
renderPassState.height = static_cast<float>(pixelh);
renderPassState.msaa = VK_SAMPLE_COUNT_1_BIT;
renderPassState.msaa = msaa;
renderPassState.numColorAttachments = static_cast<uint32_t>(rts.colors.size());
renderPassState.packedColorAttachmentFormats = 0;
for (size_t i = 0; i < rts.colors.size(); i++)
+6 -3
View File
@@ -50,6 +50,7 @@ struct ColorAttachment
{
VkFormat format = VK_FORMAT_UNDEFINED;
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
VkImageLayout msaaLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkAttachmentLoadOp loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT;
@@ -57,6 +58,7 @@ struct ColorAttachment
{
return format == attachment.format &&
layout == attachment.layout &&
msaaLayout == attachment.msaaLayout &&
loadOp == attachment.loadOp &&
msaaSamples == attachment.msaaSamples;
}
@@ -112,11 +114,11 @@ struct RenderPassConfigurationHasher
struct FramebufferConfiguration
{
std::vector<VkImageView> colorViews;
std::vector<VkImageView> colorResolveViews;
struct StaticFramebufferConfiguration
{
VkImageView depthView = VK_NULL_HANDLE;
VkImageView resolveView = VK_NULL_HANDLE;
uint32_t width = 0;
uint32_t height = 0;
@@ -126,7 +128,7 @@ struct FramebufferConfiguration
bool operator==(const FramebufferConfiguration &conf) const
{
return colorViews == conf.colorViews &&
return colorViews == conf.colorViews && colorResolveViews == conf.colorResolveViews &&
(memcmp(&staticData, &conf.staticData, sizeof(StaticFramebufferConfiguration)) == 0);
}
};
@@ -137,6 +139,7 @@ struct FramebufferConfigurationHasher
{
size_t hashes[] = {
XXH32(configuration.colorViews.data(), configuration.colorViews.size() * sizeof(VkImageView), 0),
XXH32(configuration.colorResolveViews.data(), configuration.colorResolveViews.size() * sizeof(VkImageView), 0),
XXH32(&configuration.staticData, sizeof(configuration.staticData), 0),
};
@@ -337,7 +340,7 @@ private:
VertexAttributesID attributesID,
const BufferBindings &buffers, graphics::Texture *texture,
PrimitiveType, CullMode);
void setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture);
void setRenderPass(const RenderTargets &rts, int pixelw, int pixelh);
void setDefaultRenderPass();
void startRenderPass();
void endRenderPass();
+1 -1
View File
@@ -1044,7 +1044,7 @@ void Shader::setTextureDescriptor(const UniformInfo *info, love::graphics::Textu
// Samplers may change after this call, so they're set just before the
// descriptor set is used instead of here.
VkImageView view = vkTexture != nullptr ? (VkImageView)vkTexture->getRenderTargetHandle() : VK_NULL_HANDLE;
VkImageView view = vkTexture != nullptr ? (VkImageView)vkTexture->getHandle() : VK_NULL_HANDLE;
if (view != imageInfo.imageView)
{
imageInfo.imageLayout = vkTexture != nullptr ? vkTexture->getImageLayout() : VK_IMAGE_LAYOUT_UNDEFINED;
+194 -113
View File
@@ -24,6 +24,7 @@
#include "Buffer.h"
#include <limits>
#include <array>
namespace love
{
@@ -132,7 +133,7 @@ bool Texture::loadVolatile()
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.usage = usageFlags;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.samples = msaaSamples;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
VkImageFormatListCreateInfo viewFormatsInfo{};
viewFormatsInfo.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO;
@@ -153,26 +154,54 @@ bool Texture::loadVolatile()
imageAllocationCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
if (vmaCreateImage(allocator, &imageInfo, &imageAllocationCreateInfo, &textureImage, &textureImageAllocation, nullptr) != VK_SUCCESS)
throw love::Exception("failed to create image");
if ((msaaSamples & VK_SAMPLE_COUNT_1_BIT) != 0 || readable)
{
if (vmaCreateImage(allocator, &imageInfo, &imageAllocationCreateInfo, &imageData.image, &imageData.allocation, nullptr) != VK_SUCCESS)
throw love::Exception("failed to create image");
}
if ((msaaSamples & VK_SAMPLE_COUNT_1_BIT) == 0)
{
imageInfo.samples = msaaSamples;
if (vmaCreateImage(allocator, &imageInfo, &imageAllocationCreateInfo, &msaaImageData.image, &msaaImageData.allocation, nullptr) != VK_SUCCESS)
throw love::Exception("failed to create MSAA image");
}
auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
if (computeWrite)
imageLayout = VK_IMAGE_LAYOUT_GENERAL;
imageData.layout = VK_IMAGE_LAYOUT_GENERAL;
else if (readable)
imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageData.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
else if (renderTarget && isPixelFormatDepthStencil(format))
imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
imageData.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
else if (renderTarget)
imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageData.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
else // TODO: is there a better layout for this situation?
imageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
imageData.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget,
VK_IMAGE_LAYOUT_UNDEFINED, imageLayout,
0, VK_REMAINING_MIP_LEVELS,
0, VK_REMAINING_ARRAY_LAYERS);
if (imageData.image != VK_NULL_HANDLE)
{
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget,
VK_IMAGE_LAYOUT_UNDEFINED, imageData.layout,
0, VK_REMAINING_MIP_LEVELS,
0, VK_REMAINING_ARRAY_LAYERS);
}
if (msaaImageData.image != VK_NULL_HANDLE)
{
if (renderTarget && isPixelFormatDepthStencil(format))
msaaImageData.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
else if (renderTarget)
msaaImageData.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
else // TODO: is there a better layout for this situation?
msaaImageData.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
Vulkan::cmdTransitionImageLayout(commandBuffer, msaaImageData.image, format, renderTarget,
VK_IMAGE_LAYOUT_UNDEFINED, msaaImageData.layout,
0, VK_REMAINING_MIP_LEVELS,
0, VK_REMAINING_ARRAY_LAYERS);
}
bool hasdata = slices.get(0, 0) != nullptr;
@@ -195,14 +224,20 @@ bool Texture::loadVolatile()
}
}
else
clear();
{
if (imageData.image != VK_NULL_HANDLE)
clear(imageData);
if (msaaImageData.image != VK_NULL_HANDLE)
clear(msaaImageData);
}
}
else
{
Texture *roottex = (Texture *) rootView.texture;
textureImage = roottex->textureImage;
textureImageAllocation = VK_NULL_HANDLE;
imageLayout = roottex->imageLayout;
imageData = roottex->imageData;
msaaImageData = roottex->msaaImageData;
imageData.allocation = VK_NULL_HANDLE;
msaaImageData.allocation = VK_NULL_HANDLE;
msaaSamples = roottex->msaaSamples;
}
@@ -214,34 +249,8 @@ bool Texture::loadVolatile()
if (renderTarget)
{
renderTargetImageViews.resize(getMipmapCount());
for (int mip = 0; mip < getMipmapCount(); mip++)
{
renderTargetImageViews.at(mip).resize(layerCount);
for (int slice = 0; slice < layerCount; slice++)
{
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = textureImage;
viewInfo.viewType = Vulkan::getImageViewType(getTextureType());
if (viewInfo.viewType == VK_IMAGE_VIEW_TYPE_CUBE)
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = vulkanFormat.internalFormat;
viewInfo.subresourceRange.aspectMask = imageAspect;
viewInfo.subresourceRange.baseMipLevel = mip + rootView.startMipmap;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = slice + rootView.startLayer;
viewInfo.subresourceRange.layerCount = 1;
viewInfo.components.r = vulkanFormat.swizzleR;
viewInfo.components.g = vulkanFormat.swizzleG;
viewInfo.components.b = vulkanFormat.swizzleB;
viewInfo.components.a = vulkanFormat.swizzleA;
if (vkCreateImageView(device, &viewInfo, nullptr, &renderTargetImageViews.at(mip).at(slice)) != VK_SUCCESS)
throw love::Exception("could not create render target image view");
}
}
createRenderTargetImageViews(imageData);
createRenderTargetImageViews(msaaImageData);
}
if (!debugName.empty())
@@ -253,15 +262,25 @@ bool Texture::loadVolatile()
if (root)
{
nameInfo.objectType = VK_OBJECT_TYPE_IMAGE;
nameInfo.objectHandle = (uint64_t)textureImage;
nameInfo.objectHandle = (uint64_t)imageData.image;
}
else
{
nameInfo.objectType = VK_OBJECT_TYPE_IMAGE_VIEW;
nameInfo.objectHandle = (uint64_t)textureImageView;
nameInfo.objectHandle = (uint64_t)imageData.imageView;
}
nameInfo.pObjectName = debugName.c_str();
vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
if (msaaImageData.image != VK_NULL_HANDLE && root)
{
nameInfo.objectType = VK_OBJECT_TYPE_IMAGE;
nameInfo.objectHandle = (uint64_t)msaaImageData.image;
std::string msaaName = debugName + " (MSAA buffer)";
nameInfo.pObjectName = msaaName.c_str();
vkSetDebugUtilsObjectNameEXT(device, &nameInfo);
}
}
}
@@ -272,26 +291,29 @@ bool Texture::loadVolatile()
void Texture::unloadVolatile()
{
if (textureImage == VK_NULL_HANDLE)
return;
std::array<VulkanImageData *, 2> datas = {&imageData, &msaaImageData};
vgfx->queueCleanUp([
device = device,
textureImageView = textureImageView,
allocator = allocator,
textureImage = textureImage,
textureImageAllocation = textureImageAllocation,
textureImageViews = std::move(renderTargetImageViews)] () {
vkDestroyImageView(device, textureImageView, nullptr);
if (textureImageAllocation)
vmaDestroyImage(allocator, textureImage, textureImageAllocation);
for (const auto &views : textureImageViews)
for (const auto &view : views)
vkDestroyImageView(device, view, nullptr);
});
for (const VulkanImageData *data : datas)
{
if (data->image == VK_NULL_HANDLE)
continue;
textureImage = VK_NULL_HANDLE;
textureImageAllocation = VK_NULL_HANDLE;
vgfx->queueCleanUp([
device = device,
allocator = allocator,
imageData = std::move(*data)] () {
if (imageData.imageView != VK_NULL_HANDLE)
vkDestroyImageView(device, imageData.imageView, nullptr);
if (imageData.allocation != VK_NULL_HANDLE)
vmaDestroyImage(allocator, imageData.image, imageData.allocation);
for (const auto &views : imageData.renderTargetImageViews)
for (const auto &view : views)
vkDestroyImageView(device, view, nullptr);
});
}
imageData = {};
msaaImageData = {};
updateGraphicsMemorySize(false);
}
@@ -303,7 +325,7 @@ Texture::~Texture()
ptrdiff_t Texture::getRenderTargetHandle() const
{
return (ptrdiff_t)textureImageView;
return (ptrdiff_t)imageData.image;
}
ptrdiff_t Texture::getSamplerHandle() const
@@ -313,7 +335,16 @@ ptrdiff_t Texture::getSamplerHandle() const
VkImageView Texture::getRenderTargetView(int mip, int layer)
{
return renderTargetImageViews.at(mip).at(layer);
if (imageData.renderTargetImageViews.empty())
return imageData.imageView;
return imageData.renderTargetImageViews.at(mip).at(layer);
}
VkImageView Texture::getMSAARenderTargetView(int mip, int layer)
{
if (msaaImageData.renderTargetImageViews.empty())
return msaaImageData.imageView;
return msaaImageData.renderTargetImageViews.at(mip).at(layer);
}
VkSampleCountFlagBits Texture::getMsaaSamples() const
@@ -328,7 +359,7 @@ int Texture::getMSAA() const
ptrdiff_t Texture::getHandle() const
{
return (ptrdiff_t)textureImage;
return (ptrdiff_t)imageData.imageView;
}
void Texture::setSamplerState(const SamplerState &s)
@@ -339,7 +370,12 @@ void Texture::setSamplerState(const SamplerState &s)
VkImageLayout Texture::getImageLayout() const
{
return imageLayout;
return imageData.layout;
}
VkImageLayout Texture::getMSAAImageLayout() const
{
return msaaImageData.layout;
}
void Texture::createTextureImageView()
@@ -347,7 +383,7 @@ void Texture::createTextureImageView()
auto vulkanFormat = Vulkan::getTextureFormat(format);
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = textureImage;
viewInfo.image = imageData.image;
viewInfo.viewType = Vulkan::getImageViewType(getTextureType());
viewInfo.format = vulkanFormat.internalFormat;
viewInfo.subresourceRange.aspectMask = imageAspect;
@@ -364,11 +400,56 @@ void Texture::createTextureImageView()
viewInfo.components.b = vulkanFormat.swizzleB;
viewInfo.components.a = vulkanFormat.swizzleA;
if (vkCreateImageView(device, &viewInfo, nullptr, &textureImageView) != VK_SUCCESS)
throw love::Exception("could not create texture image view");
imageData.imageView = VK_NULL_HANDLE;
if (imageData.image != VK_NULL_HANDLE && readable)
{
if (vkCreateImageView(device, &viewInfo, nullptr, &imageData.imageView) != VK_SUCCESS)
throw love::Exception("could not create texture image view");
}
}
void Texture::clear()
void Texture::createRenderTargetImageViews(VulkanImageData &data)
{
if (data.image == VK_NULL_HANDLE || (getMipmapCount() == 1 && layerCount == 1 && data.imageView != VK_NULL_HANDLE))
{
// Reuse the main image view in this situation, if it exists.
data.renderTargetImageViews.clear();
return;
}
auto vulkanFormat = Vulkan::getTextureFormat(format);
data.renderTargetImageViews.resize(getMipmapCount());
for (int mip = 0; mip < getMipmapCount(); mip++)
{
data.renderTargetImageViews.at(mip).resize(layerCount);
for (int slice = 0; slice < layerCount; slice++)
{
VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = data.image;
viewInfo.viewType = Vulkan::getImageViewType(getTextureType());
if (viewInfo.viewType == VK_IMAGE_VIEW_TYPE_CUBE)
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = vulkanFormat.internalFormat;
viewInfo.subresourceRange.aspectMask = imageAspect;
viewInfo.subresourceRange.baseMipLevel = mip + rootView.startMipmap;
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = slice + rootView.startLayer;
viewInfo.subresourceRange.layerCount = 1;
viewInfo.components.r = vulkanFormat.swizzleR;
viewInfo.components.g = vulkanFormat.swizzleG;
viewInfo.components.b = vulkanFormat.swizzleB;
viewInfo.components.a = vulkanFormat.swizzleA;
if (vkCreateImageView(device, &viewInfo, nullptr, &data.renderTargetImageViews.at(mip).at(slice)) != VK_SUCCESS)
throw love::Exception("could not create render target image view");
}
}
}
void Texture::clear(const VulkanImageData &data)
{
auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
@@ -379,12 +460,12 @@ void Texture::clear()
range.baseArrayLayer = 0;
range.layerCount = VK_REMAINING_ARRAY_LAYERS;
VkImageLayout clearLayout = imageLayout == VK_IMAGE_LAYOUT_GENERAL ? imageLayout : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
VkImageLayout clearLayout = data.layout == VK_IMAGE_LAYOUT_GENERAL ? data.layout : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
if (clearLayout != imageLayout)
if (clearLayout != data.layout)
{
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget,
imageLayout, clearLayout,
Vulkan::cmdTransitionImageLayout(commandBuffer, data.image, format, renderTarget,
data.layout, clearLayout,
0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
}
@@ -393,18 +474,18 @@ void Texture::clear()
VkClearDepthStencilValue depthStencilColor{};
depthStencilColor.depth = 0.0f;
depthStencilColor.stencil = 0;
vkCmdClearDepthStencilImage(commandBuffer, textureImage, clearLayout, &depthStencilColor, 1, &range);
vkCmdClearDepthStencilImage(commandBuffer, data.image, clearLayout, &depthStencilColor, 1, &range);
}
else
{
auto clearColor = getClearColor(this, ColorD(0, 0, 0, 0));
vkCmdClearColorImage(commandBuffer, textureImage, clearLayout, &clearColor, 1, &range);
vkCmdClearColorImage(commandBuffer, data.image, clearLayout, &clearColor, 1, &range);
}
if (clearLayout != imageLayout)
if (clearLayout != data.layout)
{
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget,
clearLayout, imageLayout,
Vulkan::cmdTransitionImageLayout(commandBuffer, data.image, format, renderTarget,
clearLayout, data.layout,
0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
}
}
@@ -450,15 +531,15 @@ void Texture::generateMipmapsInternal()
{
auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget,
imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
if (imageData.layout != VK_IMAGE_LAYOUT_GENERAL)
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget,
imageData.layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
rootView.startMipmap, static_cast<uint32_t>(getMipmapCount()),
rootView.startLayer, static_cast<uint32_t>(layerCount));
VkImageMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.image = textureImage;
barrier.image = imageData.image;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
@@ -477,7 +558,7 @@ void Texture::generateMipmapsInternal()
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
if (imageData.layout != VK_IMAGE_LAYOUT_GENERAL)
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
0, nullptr,
0, nullptr,
@@ -498,29 +579,29 @@ void Texture::generateMipmapsInternal()
blit.dstSubresource.baseArrayLayer = rootView.startLayer;
blit.dstSubresource.layerCount = static_cast<uint32_t>(layerCount);
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
if (imageData.layout != VK_IMAGE_LAYOUT_GENERAL)
{
vkCmdBlitImage(commandBuffer,
textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
imageData.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
imageData.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &blit,
VK_FILTER_LINEAR);
}
else
{
vkCmdBlitImage(commandBuffer,
textureImage, VK_IMAGE_LAYOUT_GENERAL,
textureImage, VK_IMAGE_LAYOUT_GENERAL,
imageData.image, VK_IMAGE_LAYOUT_GENERAL,
imageData.image, VK_IMAGE_LAYOUT_GENERAL,
1, &blit,
VK_FILTER_LINEAR);
}
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.newLayout = imageLayout;
barrier.newLayout = imageData.layout;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
if (imageData.layout != VK_IMAGE_LAYOUT_GENERAL)
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
0, nullptr,
0, nullptr,
@@ -529,11 +610,11 @@ void Texture::generateMipmapsInternal()
barrier.subresourceRange.baseMipLevel = rootView.startMipmap + mipLevels - 1;
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.newLayout = imageLayout;
barrier.newLayout = imageData.layout;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
if (imageData.layout != VK_IMAGE_LAYOUT_GENERAL)
vkCmdPipelineBarrier(commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
0, nullptr,
@@ -587,31 +668,31 @@ void Texture::uploadByteData(const void *data, size_t size, int level, int slice
auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
if (imageData.layout != VK_IMAGE_LAYOUT_GENERAL)
{
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget,
imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget,
imageData.layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
level, 1, baseLayer, 1);
vkCmdCopyBufferToImage(
commandBuffer,
stagingBuffer,
textureImage,
imageData.image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&region
);
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageLayout,
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageData.layout,
level, 1, baseLayer, 1);
}
else
vkCmdCopyBufferToImage(
commandBuffer,
stagingBuffer,
textureImage,
imageLayout,
imageData.image,
imageData.layout,
1,
&region
);
@@ -641,16 +722,16 @@ void Texture::copyFromBuffer(graphics::Buffer *source, size_t sourceoffset, int
region.imageExtent.width = static_cast<uint32_t>(rect.w);
region.imageExtent.height = static_cast<uint32_t>(rect.h);
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
if (imageData.layout != VK_IMAGE_LAYOUT_GENERAL)
{
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, layers.mipLevel, 1, layers.baseArrayLayer, 1);
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget, imageData.layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, layers.mipLevel, 1, layers.baseArrayLayer, 1);
vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), imageData.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageLayout, layers.mipLevel, 1, layers.baseArrayLayer, 1);
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageData.layout, layers.mipLevel, 1, layers.baseArrayLayer, 1);
}
else
vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), textureImage, VK_IMAGE_LAYOUT_GENERAL, 1, &region);
vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), imageData.image, VK_IMAGE_LAYOUT_GENERAL, 1, &region);
}
void Texture::copyToBuffer(graphics::Buffer *dest, int slice, int mipmap, const Rect &rect, size_t destoffset, int destwidth, size_t size)
@@ -674,16 +755,16 @@ void Texture::copyToBuffer(graphics::Buffer *dest, int slice, int mipmap, const
region.imageExtent.height = static_cast<uint32_t>(rect.h);
region.imageExtent.depth = 1;
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
if (imageData.layout != VK_IMAGE_LAYOUT_GENERAL)
{
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, imageLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, layers.mipLevel, 1, layers.baseArrayLayer, 1);
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget, imageData.layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, layers.mipLevel, 1, layers.baseArrayLayer, 1);
vkCmdCopyImageToBuffer(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, (VkBuffer) dest->getHandle(), 1, &region);
vkCmdCopyImageToBuffer(commandBuffer, imageData.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, (VkBuffer) dest->getHandle(), 1, &region);
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageLayout, layers.mipLevel, 1, layers.baseArrayLayer, 1);
Vulkan::cmdTransitionImageLayout(commandBuffer, imageData.image, format, renderTarget, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageData.layout, layers.mipLevel, 1, layers.baseArrayLayer, 1);
}
else
vkCmdCopyImageToBuffer(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, (VkBuffer)dest->getHandle(), 1, &region);
vkCmdCopyImageToBuffer(commandBuffer, imageData.image, VK_IMAGE_LAYOUT_GENERAL, (VkBuffer)dest->getHandle(), 1, &region);
// TODO: This could be combined with the cmdTransitionImageLayout barrier.
((Buffer *)dest)->postGPUWriteBarrier(commandBuffer);
+16 -6
View File
@@ -51,6 +51,7 @@ public:
void setSamplerState(const SamplerState &s) override;
VkImageLayout getImageLayout() const;
VkImageLayout getMSAAImageLayout() const;
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;
@@ -59,6 +60,7 @@ public:
ptrdiff_t getSamplerHandle() const override;
VkImageView getRenderTargetView(int mip, int layer);
VkImageView getMSAARenderTargetView(int mip, int layer);
VkSampleCountFlagBits getMsaaSamples() const;
void uploadByteData(const void *data, size_t size, int level, int slice, const Rect &r) override;
@@ -71,18 +73,26 @@ public:
static VkClearColorValue getClearColor(love::graphics::Texture *texture, const ColorD &color);
private:
struct VulkanImageData
{
VkImage image = VK_NULL_HANDLE;
VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
VmaAllocation allocation = VK_NULL_HANDLE;
VkImageView imageView = VK_NULL_HANDLE;
std::vector<std::vector<VkImageView>> renderTargetImageViews;
};
void createTextureImageView();
void clear();
void createRenderTargetImageViews(VulkanImageData &data);
void clear(const VulkanImageData &data);
Graphics *vgfx = nullptr;
VkDevice device = VK_NULL_HANDLE;
VkImageAspectFlags imageAspect;
VmaAllocator allocator = VK_NULL_HANDLE;
VkImage textureImage = VK_NULL_HANDLE;
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VmaAllocation textureImageAllocation = VK_NULL_HANDLE;
VkImageView textureImageView = VK_NULL_HANDLE;
std::vector<std::vector<VkImageView>> renderTargetImageViews;
VulkanImageData imageData;
VulkanImageData msaaImageData;
VkSampler textureSampler = VK_NULL_HANDLE;
Slices slices;
int layerCount = 0;
+22 -22
View File
@@ -822,22 +822,22 @@ VkIndexType Vulkan::getVulkanIndexBufferType(IndexDataType type)
}
}
void Vulkan::setImageLayoutTransitionOptions(bool previous, bool renderTarget, bool depthStencil, VkImageLayout layout, VkAccessFlags &accessMask, VkPipelineStageFlags &stageFlags)
void Vulkan::addImageLayoutTransitionOptions(bool previous, bool renderTarget, bool depthStencil, VkImageLayout layout, VkAccessFlags &accessMask, VkPipelineStageFlags &stageFlags)
{
switch (layout)
{
case VK_IMAGE_LAYOUT_UNDEFINED:
accessMask = 0;
accessMask |= 0;
if (previous)
stageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
stageFlags |= VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
else
stageFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
stageFlags |= VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
break;
case VK_IMAGE_LAYOUT_GENERAL:
// We use the general image layout for images that are both compute write and readable.
// todo: can we optimize this?
accessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
stageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
accessMask |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT;
stageFlags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
if (renderTarget)
{
if (depthStencil)
@@ -853,28 +853,28 @@ void Vulkan::setImageLayoutTransitionOptions(bool previous, bool renderTarget, b
}
break;
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
accessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
stageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
accessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
stageFlags |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
accessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
stageFlags = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
accessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
stageFlags |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
break;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
accessMask = VK_ACCESS_SHADER_READ_BIT;
stageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
accessMask |= VK_ACCESS_SHADER_READ_BIT;
stageFlags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
accessMask = VK_ACCESS_TRANSFER_READ_BIT;
stageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
accessMask |= VK_ACCESS_TRANSFER_READ_BIT;
stageFlags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
accessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
stageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
accessMask |= VK_ACCESS_TRANSFER_WRITE_BIT;
stageFlags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
accessMask = 0;
stageFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
accessMask |= 0;
stageFlags |= VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
break;
default:
throw love::Exception("unimplemented image layout");
@@ -897,11 +897,11 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima
const PixelFormatInfo &info = getPixelFormatInfo(format);
VkPipelineStageFlags sourceStage;
VkPipelineStageFlags destinationStage;
VkPipelineStageFlags sourceStage = 0;
VkPipelineStageFlags destinationStage = 0;
setImageLayoutTransitionOptions(true, renderTarget, info.depth || info.stencil, oldLayout, barrier.srcAccessMask, sourceStage);
setImageLayoutTransitionOptions(false, renderTarget, info.depth || info.stencil, newLayout, barrier.dstAccessMask, destinationStage);
addImageLayoutTransitionOptions(true, renderTarget, info.depth || info.stencil, oldLayout, barrier.srcAccessMask, sourceStage);
addImageLayoutTransitionOptions(false, renderTarget, info.depth || info.stencil, newLayout, barrier.dstAccessMask, destinationStage);
if (info.color)
barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT;
+2 -2
View File
@@ -80,8 +80,8 @@ public:
static VkStencilOp getStencilOp(StencilAction);
static VkIndexType getVulkanIndexBufferType(IndexDataType type);
static void setImageLayoutTransitionOptions(
bool previous, bool renderTarget, bool depthStencil, VkImageLayout layout, VkAccessFlags &accessMask, VkPipelineStageFlags &stageFlags);
static void addImageLayoutTransitionOptions(
bool previous, bool renderTarget, bool depthStencil, VkImageLayout layout, VkAccessFlags& accessMask, VkPipelineStageFlags& stageFlags);
static void cmdTransitionImageLayout(
VkCommandBuffer, VkImage, PixelFormat format, bool renderTarget, VkImageLayout oldLayout, VkImageLayout newLayout,