vulkan: memory barrier after compute dispatches.

This commit is contained in:
Sasha Szpakowski
2024-09-30 19:58:45 -03:00
parent 64e4eaec74
commit 1ee89154c0
9 changed files with 184 additions and 81 deletions
+32 -37
View File
@@ -62,6 +62,36 @@ Buffer::Buffer(love::graphics::Graphics *gfx, const Settings &settings, const st
, vgfx(dynamic_cast<Graphics*>(gfx))
, usageFlags(settings.usageFlags)
{
// All buffers can be copied to and from.
barrierDstAccessFlags = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
barrierDstStageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
if (usageFlags & BUFFERUSAGEFLAG_VERTEX)
{
barrierDstAccessFlags |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
barrierDstStageFlags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
}
if (usageFlags & BUFFERUSAGEFLAG_INDEX)
{
barrierDstAccessFlags |= VK_ACCESS_INDEX_READ_BIT;
barrierDstStageFlags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
}
if (usageFlags & BUFFERUSAGEFLAG_TEXEL)
{
barrierDstAccessFlags |= VK_ACCESS_SHADER_READ_BIT;
barrierDstStageFlags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
}
if (usageFlags & BUFFERUSAGEFLAG_SHADER_STORAGE)
{
barrierDstAccessFlags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
barrierDstStageFlags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
}
if (usageFlags & BUFFERUSAGEFLAG_INDIRECT_ARGUMENTS)
{
barrierDstAccessFlags |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
barrierDstStageFlags |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
}
loadVolatile();
}
@@ -302,44 +332,9 @@ void Buffer::postGPUWriteBarrier(VkCommandBuffer cmd)
VkMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = barrierDstAccessFlags;
VkPipelineStageFlags dstStageMask = 0;
addPostGPUWriteBarrierFlags(barrier.dstAccessMask, dstStageMask);
vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask, 0, 1, &barrier, 0, nullptr, 0, nullptr);
}
void Buffer::addPostGPUWriteBarrierFlags(VkAccessFlags &dstAccessFlags, VkPipelineStageFlags &dstStageFlags)
{
// All buffers can be copied to and from.
dstAccessFlags |= VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
dstStageFlags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
if (usageFlags & BUFFERUSAGEFLAG_VERTEX)
{
dstAccessFlags |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
dstStageFlags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
}
if (usageFlags & BUFFERUSAGEFLAG_INDEX)
{
dstAccessFlags |= VK_ACCESS_INDEX_READ_BIT;
dstStageFlags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
}
if (usageFlags & BUFFERUSAGEFLAG_TEXEL)
{
dstAccessFlags |= VK_ACCESS_SHADER_READ_BIT;
dstStageFlags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
}
if (usageFlags & BUFFERUSAGEFLAG_SHADER_STORAGE)
{
dstAccessFlags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
dstStageFlags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
}
if (usageFlags & BUFFERUSAGEFLAG_INDIRECT_ARGUMENTS)
{
dstAccessFlags |= VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
dstStageFlags |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
}
vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, barrierDstStageFlags, 0, 1, &barrier, 0, nullptr, 0, nullptr);
}
} // vulkan
+6 -1
View File
@@ -56,7 +56,9 @@ public:
ptrdiff_t getTexelBufferHandle() const override;
void postGPUWriteBarrier(VkCommandBuffer cmd);
void addPostGPUWriteBarrierFlags(VkAccessFlags &dstAccessFlags, VkPipelineStageFlags &dstStageFlags);
VkAccessFlags getBarrierDstAccessFlags() const { return barrierDstAccessFlags; }
VkPipelineStageFlags getBarrierDstStageFlags() const { return barrierDstStageFlags; }
private:
@@ -76,6 +78,9 @@ private:
BufferUsageFlags usageFlags;
Range mappedRange;
bool coherent;
VkAccessFlags barrierDstAccessFlags = 0;
VkPipelineStageFlags barrierDstStageFlags = 0;
};
} // vulkan
+78 -20
View File
@@ -351,7 +351,7 @@ void Graphics::submitGpuCommands(SubmitMode submitMode, void *screenshotCallback
Vulkan::cmdTransitionImageLayout(
commandBuffers.at(currentFrame),
backbufferImage,
swapChainPixelFormat,
swapChainPixelFormat, true,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
}
@@ -382,7 +382,7 @@ void Graphics::submitGpuCommands(SubmitMode submitMode, void *screenshotCallback
Vulkan::cmdTransitionImageLayout(
commandBuffers.at(currentFrame),
backbufferImage,
swapChainPixelFormat,
swapChainPixelFormat, true,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
@@ -405,7 +405,7 @@ void Graphics::submitGpuCommands(SubmitMode submitMode, void *screenshotCallback
Vulkan::cmdTransitionImageLayout(
commandBuffers.at(currentFrame),
backbufferImage,
swapChainPixelFormat,
swapChainPixelFormat, true,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
fakeBackbuffer == nullptr ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
}
@@ -1194,8 +1194,56 @@ graphics::StreamBuffer *Graphics::newStreamBuffer(BufferUsage type, size_t size)
return new StreamBuffer(this, type, size);
}
static bool computeDispatchBarrierFlags(Shader *shader, VkAccessFlags &dstAccessFlags, VkPipelineStageFlags &dstStageFlags)
{
for (const auto &info : shader->getActiveTextureInfo())
{
if ((info.access & Shader::ACCESS_WRITE) == 0)
continue;
if (info.texture == nullptr)
return false;
auto tex = (Texture *) info.texture;
// All writable images use the GENERAL layout.
// TODO: this is pretty messy.
VkAccessFlags texAccessFlags = 0;
VkPipelineStageFlags texStageFlags = 0;
const PixelFormatInfo &info = getPixelFormatInfo(tex->getPixelFormat());
Vulkan::setImageLayoutTransitionOptions(false, tex->isRenderTarget(), info, VK_IMAGE_LAYOUT_GENERAL, texAccessFlags, texStageFlags);
dstAccessFlags |= texAccessFlags;
dstStageFlags |= texStageFlags;
}
for (const auto &info : shader->getActiveStorageBufferInfo())
{
if ((info.access & Shader::ACCESS_WRITE) == 0)
continue;
if (info.buffer == nullptr)
return false;
auto b = (Buffer *) info.buffer;
dstAccessFlags |= b->getBarrierDstAccessFlags();
dstStageFlags |= b->getBarrierDstStageFlags();
}
return true;
}
bool Graphics::dispatch(love::graphics::Shader *shader, int x, int y, int z)
{
auto computeShader = (Shader *) shader;
VkMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
VkPipelineStageFlags dstStageMask = 0;
if (!computeDispatchBarrierFlags(computeShader, barrier.dstAccessMask, dstStageMask))
return false;
usedShadersInFrame.insert(computeShader);
if (renderPassState.active)
@@ -1205,14 +1253,26 @@ bool Graphics::dispatch(love::graphics::Shader *shader, int x, int y, int z)
computeShader->cmdPushDescriptorSets(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_COMPUTE);
// TODO: does this need any layout transitions?
vkCmdDispatch(commandBuffers.at(currentFrame), (uint32) x, (uint32) y, (uint32) z);
// Image layout transitions aren't needed, every writable image will be in the GENERAL layout.
if (barrier.dstAccessMask != 0 || dstStageMask != 0)
vkCmdPipelineBarrier(commandBuffers.at(currentFrame), VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, dstStageMask, 0, 1, &barrier, 0, nullptr, 0, nullptr);
return true;
}
bool Graphics::dispatch(love::graphics::Shader *shader, love::graphics::Buffer *indirectargs, size_t argsoffset)
{
auto computeShader = (Shader *) shader;
VkMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
VkPipelineStageFlags dstStageMask = 0;
if (!computeDispatchBarrierFlags(computeShader, barrier.dstAccessMask, dstStageMask))
return false;
usedShadersInFrame.insert(computeShader);
if (renderPassState.active)
@@ -1222,9 +1282,12 @@ bool Graphics::dispatch(love::graphics::Shader *shader, love::graphics::Buffer *
computeShader->cmdPushDescriptorSets(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_COMPUTE);
// TODO: does this need any layout transitions?
vkCmdDispatchIndirect(commandBuffers.at(currentFrame), (VkBuffer) indirectargs->getHandle(), argsoffset);
// Image layout transitions aren't needed, every writable image will be in the GENERAL layout.
if (barrier.dstAccessMask != 0 || dstStageMask != 0)
vkCmdPipelineBarrier(commandBuffers.at(currentFrame), VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, dstStageMask, 0, 1, &barrier, 0, nullptr, 0, nullptr);
return true;
}
@@ -1315,7 +1378,7 @@ void Graphics::beginFrame()
Vulkan::cmdTransitionImageLayout(
commandBuffers.at(currentFrame),
swapChainImages[imageIndex],
swapChainPixelFormat,
swapChainPixelFormat, true,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
}
@@ -1326,7 +1389,7 @@ void Graphics::beginFrame()
Vulkan::cmdTransitionImageLayout(
commandBuffers.at(currentFrame),
depthImage,
depthStencilPixelFormat,
depthStencilPixelFormat, true,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
@@ -1334,7 +1397,7 @@ void Graphics::beginFrame()
Vulkan::cmdTransitionImageLayout(
commandBuffers.at(currentFrame),
colorImage,
swapChainPixelFormat,
swapChainPixelFormat, true,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
@@ -2503,7 +2566,7 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b
FramebufferConfiguration configuration{};
std::vector<std::tuple<VkImage, PixelFormat, VkImageLayout, VkImageLayout, int, int>> transitionImages;
std::vector<std::tuple<VkImage, PixelFormat, bool, VkImageLayout, VkImageLayout, int, int>> transitionImages;
for (const auto &color : rts.colors)
{
@@ -2513,7 +2576,7 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b
VkImageLayout imagelayout = tex->getImageLayout();
if (imagelayout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
{
transitionImages.push_back({ (VkImage)tex->getHandle(), tex->getPixelFormat(), imagelayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
transitionImages.push_back({ (VkImage)tex->getHandle(), tex->getPixelFormat(), tex->isRenderTarget(), imagelayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
viewinfo.startMipmap + color.mipmap, viewinfo.startLayer + color.slice });
}
}
@@ -2525,7 +2588,7 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b
VkImageLayout imagelayout = tex->getImageLayout();
if (imagelayout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
{
transitionImages.push_back({ (VkImage)tex->getHandle(), tex->getPixelFormat(), imagelayout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
transitionImages.push_back({ (VkImage)tex->getHandle(), tex->getPixelFormat(), tex->isRenderTarget(), imagelayout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
viewinfo.startMipmap + rts.depthStencil.mipmap, viewinfo.startLayer + rts.depthStencil.slice });
}
}
@@ -2581,8 +2644,8 @@ void Graphics::startRenderPass()
renderPassState.framebufferConfiguration.staticData.renderPass = renderPassState.beginInfo.renderPass;
renderPassState.beginInfo.framebuffer = getFramebuffer(renderPassState.framebufferConfiguration);
for (const auto &[image, format, imageLayout, renderLayout, rootmip, rootlayer] : renderPassState.transitionImages)
Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, format, imageLayout, renderLayout, rootmip, 1, rootlayer, 1);
for (const auto &[image, format, renderTarget, imageLayout, renderLayout, rootmip, rootlayer] : renderPassState.transitionImages)
Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, format, renderTarget, imageLayout, renderLayout, rootmip, 1, rootlayer, 1);
vkCmdBeginRenderPass(commandBuffers.at(currentFrame), &renderPassState.beginInfo, VK_SUBPASS_CONTENTS_INLINE);
@@ -2595,8 +2658,8 @@ void Graphics::endRenderPass()
vkCmdEndRenderPass(commandBuffers.at(currentFrame));
for (const auto &[image, format, imageLayout, renderLayout, rootmip, rootlayer] : renderPassState.transitionImages)
Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, format, renderLayout, imageLayout, rootmip, 1, rootlayer, 1);
for (const auto &[image, format, renderTarget, imageLayout, renderLayout, rootmip, rootlayer] : renderPassState.transitionImages)
Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, format, renderTarget, renderLayout, imageLayout, rootmip, 1, rootlayer, 1);
for (auto &colorAttachment : renderPassState.renderPassConfiguration.colorAttachments)
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
@@ -2686,11 +2749,6 @@ void Graphics::requestSwapchainRecreation()
}
}
void Graphics::setComputeShader(Shader *shader)
{
computeShader = shader;
}
VkSampler Graphics::getCachedSampler(const SamplerState &samplerState)
{
auto samplerkey = samplerState.toKey();
+1 -3
View File
@@ -196,7 +196,7 @@ struct RenderpassState
RenderPassConfiguration renderPassConfiguration{};
FramebufferConfiguration framebufferConfiguration{};
VkPipeline pipeline = VK_NULL_HANDLE;
std::vector<std::tuple<VkImage, PixelFormat, VkImageLayout, VkImageLayout, int, int>> transitionImages;
std::vector<std::tuple<VkImage, PixelFormat, bool, VkImageLayout, VkImageLayout, int, int>> transitionImages;
uint32_t numColorAttachments = 0;
uint64 packedColorAttachmentFormats = 0;
float width = 0.0f;
@@ -267,7 +267,6 @@ public:
void addReadbackCallback(std::function<void()> callback);
void submitGpuCommands(SubmitMode, void *screenshotCallbackData = nullptr);
VkSampler getCachedSampler(const SamplerState &sampler);
void setComputeShader(Shader *computeShader);
graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData();
const OptionalDeviceExtensions &getEnabledOptionalDeviceExtensions() const;
const OptionalInstanceExtensions &getEnabledOptionalInstanceExtensions() const;
@@ -377,7 +376,6 @@ private:
std::unordered_map<uint64, VkSampler> samplers;
VkCommandPool commandPool = VK_NULL_HANDLE;
std::vector<VkCommandBuffer> commandBuffers;
Shader *computeShader = nullptr;
std::vector<VkSemaphore> imageAvailableSemaphores;
std::vector<VkSemaphore> renderFinishedSemaphores;
std::vector<VkFence> inFlightFences;
+14 -2
View File
@@ -337,8 +337,6 @@ void Shader::attach()
Vulkan::shaderSwitch();
}
}
else
vgfx->setComputeShader(this);
}
int Shader::getVertexAttributeIndex(const std::string &name)
@@ -777,12 +775,18 @@ void Shader::compileShaders()
descriptorBufferViews.clear();
descriptorBufferViews.reserve(numBufferViews);
allTextureInfo.clear();
allTextureInfo.reserve(numTextures);
storageBufferInfo.clear();
storageBufferInfo.reserve(numBuffers);
if (localUniformData.size() > 0)
{
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.range = localUniformData.size();
descriptorBuffers.push_back(bufferInfo);
storageBufferInfo.push_back({ nullptr, ACCESS_READ }); // Dummy value.
VkWriteDescriptorSet write{};
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
@@ -807,6 +811,8 @@ void Shader::compileShaders()
VkDescriptorImageInfo imageInfo{};
descriptorImages.push_back(imageInfo);
allTextureInfo.push_back({ nullptr, info.access });
auto texture = activeTextures[info.resourceIndex + i];
if (texture != nullptr)
setTextureDescriptor(&info, texture, i);
@@ -836,6 +842,8 @@ void Shader::compileShaders()
VkDescriptorImageInfo imageInfo{};
descriptorImages.push_back(imageInfo);
allTextureInfo.push_back({ nullptr, info.access });
auto texture = activeTextures[info.resourceIndex + i];
if (texture != nullptr)
setTextureDescriptor(&info, texture, i);
@@ -893,6 +901,8 @@ void Shader::compileShaders()
VkDescriptorBufferInfo bufferInfo{};
descriptorBuffers.push_back(bufferInfo);
storageBufferInfo.push_back({ nullptr, info.access });
auto buffer = activeBuffers[info.resourceIndex + i];
if (buffer != nullptr)
setBufferDescriptor(&info, buffer, i);
@@ -1039,6 +1049,7 @@ void Shader::setTextureDescriptor(const UniformInfo *info, love::graphics::Textu
{
imageInfo.imageLayout = vkTexture != nullptr ? vkTexture->getImageLayout() : VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.imageView = view;
allTextureInfo[info->bindingStartIndex + index].texture = texture;
resourceDescriptorsDirty = true;
}
}
@@ -1055,6 +1066,7 @@ void Shader::setBufferDescriptor(const UniformInfo *info, love::graphics::Buffer
bufferInfo.buffer = vkbuffer;
bufferInfo.offset = 0;
bufferInfo.range = range;
storageBufferInfo[info->bindingStartIndex + index].buffer = buffer;
resourceDescriptorsDirty = true;
}
}
+18
View File
@@ -124,6 +124,18 @@ public:
DataBaseType baseType;
};
struct TextureInfo
{
love::graphics::Texture *texture;
Access access;
};
struct BufferInfo
{
love::graphics::Buffer *buffer;
Access access;
};
Shader(StrongRef<love::graphics::ShaderStage> stages[], const CompileOptions &options);
virtual ~Shader();
@@ -158,6 +170,9 @@ public:
VkPipeline getCachedGraphicsPipeline(Graphics *vgfx, const GraphicsPipelineConfigurationCore &configuration);
VkPipeline getCachedGraphicsPipeline(Graphics *vgfx, const GraphicsPipelineConfigurationFull &configuration);
const std::vector<TextureInfo> &getActiveTextureInfo() const { return allTextureInfo; }
const std::vector<BufferInfo> &getActiveStorageBufferInfo() const { return storageBufferInfo; }
private:
void compileShaders();
void createDescriptorSetLayout();
@@ -189,6 +204,9 @@ private:
std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
std::vector<VkShaderModule> shaderModules;
std::vector<TextureInfo> allTextureInfo;
std::vector<BufferInfo> storageBufferInfo;
Graphics *vgfx = nullptr;
VkDevice device = VK_NULL_HANDLE;
+10 -10
View File
@@ -169,7 +169,7 @@ bool Texture::loadVolatile()
else // TODO: is there a better layout for this situation?
imageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format,
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget,
VK_IMAGE_LAYOUT_UNDEFINED, imageLayout,
0, VK_REMAINING_MIP_LEVELS,
0, VK_REMAINING_ARRAY_LAYERS);
@@ -383,7 +383,7 @@ void Texture::clear()
if (clearLayout != imageLayout)
{
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format,
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget,
imageLayout, clearLayout,
0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
}
@@ -403,7 +403,7 @@ void Texture::clear()
if (clearLayout != imageLayout)
{
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format,
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget,
clearLayout, imageLayout,
0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
}
@@ -451,7 +451,7 @@ void Texture::generateMipmapsInternal()
auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format,
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget,
imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
rootView.startMipmap, static_cast<uint32_t>(getMipmapCount()),
rootView.startLayer, static_cast<uint32_t>(layerCount));
@@ -589,7 +589,7 @@ void Texture::uploadByteData(const void *data, size_t size, int level, int slice
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
{
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format,
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget,
imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
level, 1, baseLayer, 1);
@@ -602,7 +602,7 @@ void Texture::uploadByteData(const void *data, size_t size, int level, int slice
&region
);
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format,
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageLayout,
level, 1, baseLayer, 1);
}
@@ -643,11 +643,11 @@ void Texture::copyFromBuffer(graphics::Buffer *source, size_t sourceoffset, int
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
{
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, layers.mipLevel, 1, layers.baseArrayLayer, 1);
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, imageLayout, 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);
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageLayout, layers.mipLevel, 1, layers.baseArrayLayer, 1);
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageLayout, layers.mipLevel, 1, layers.baseArrayLayer, 1);
}
else
vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), textureImage, VK_IMAGE_LAYOUT_GENERAL, 1, &region);
@@ -676,11 +676,11 @@ void Texture::copyToBuffer(graphics::Buffer *dest, int slice, int mipmap, const
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL)
{
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, imageLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, layers.mipLevel, 1, layers.baseArrayLayer, 1);
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, imageLayout, 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);
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageLayout, layers.mipLevel, 1, layers.baseArrayLayer, 1);
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, renderTarget, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageLayout, layers.mipLevel, 1, layers.baseArrayLayer, 1);
}
else
vkCmdCopyImageToBuffer(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, (VkBuffer)dest->getHandle(), 1, &region);
+21 -7
View File
@@ -822,7 +822,7 @@ VkIndexType Vulkan::getVulkanIndexBufferType(IndexDataType type)
}
}
static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout, VkAccessFlags &accessMask, VkPipelineStageFlags &stageFlags)
void Vulkan::setImageLayoutTransitionOptions(bool previous, bool renderTarget, const PixelFormatInfo &info, VkImageLayout layout, VkAccessFlags &accessMask, VkPipelineStageFlags &stageFlags)
{
switch (layout)
{
@@ -837,7 +837,20 @@ static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout,
// 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_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_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 (info.color)
{
accessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
stageFlags |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
}
if (info.depth || info.stencil)
{
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_COLOR_ATTACHMENT_OPTIMAL:
accessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
@@ -849,7 +862,7 @@ static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout,
break;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
accessMask = VK_ACCESS_SHADER_READ_BIT;
stageFlags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_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;
@@ -868,7 +881,7 @@ static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout,
}
}
void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, PixelFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount)
void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, PixelFormat format, bool renderTarget, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount)
{
VkImageMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
@@ -882,13 +895,14 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima
barrier.subresourceRange.baseArrayLayer = baseLayer;
barrier.subresourceRange.layerCount = layerCount;
const PixelFormatInfo &info = getPixelFormatInfo(format);
VkPipelineStageFlags sourceStage;
VkPipelineStageFlags destinationStage;
setImageLayoutTransitionOptions(true, oldLayout, barrier.srcAccessMask, sourceStage);
setImageLayoutTransitionOptions(false, newLayout, barrier.dstAccessMask, destinationStage);
setImageLayoutTransitionOptions(true, renderTarget, info, oldLayout, barrier.srcAccessMask, sourceStage);
setImageLayoutTransitionOptions(false, renderTarget, info, newLayout, barrier.dstAccessMask, destinationStage);
const PixelFormatInfo &info = getPixelFormatInfo(format);
if (info.color)
barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT;
if (info.depth)
+4 -1
View File
@@ -80,8 +80,11 @@ public:
static VkStencilOp getStencilOp(StencilAction);
static VkIndexType getVulkanIndexBufferType(IndexDataType type);
static void setImageLayoutTransitionOptions(
bool previous, bool renderTarget, const PixelFormatInfo &info, VkImageLayout layout, VkAccessFlags &accessMask, VkPipelineStageFlags &stageFlags);
static void cmdTransitionImageLayout(
VkCommandBuffer, VkImage, PixelFormat format, VkImageLayout oldLayout, VkImageLayout newLayout,
VkCommandBuffer, VkImage, PixelFormat format, bool renderTarget, VkImageLayout oldLayout, VkImageLayout newLayout,
uint32_t baseLevel = 0, uint32_t levelCount = VK_REMAINING_MIP_LEVELS, uint32_t baseLayer = 0, uint32_t layerCount = VK_REMAINING_ARRAY_LAYERS);
};