mirror of
https://github.com/love2d/love.git
synced 2026-08-12 08:30:56 +02:00
vulkan: memory barrier after compute dispatches.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
®ion
|
||||
);
|
||||
|
||||
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, ®ion);
|
||||
|
||||
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, ®ion);
|
||||
@@ -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, ®ion);
|
||||
|
||||
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, ®ion);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user