vulkan: add support for custom depth/stencil tex

This commit is contained in:
niki
2022-09-11 01:57:23 +02:00
parent 816e3f01a2
commit 1658c89f3d
5 changed files with 114 additions and 42 deletions
+15 -3
View File
@@ -240,6 +240,11 @@ void Graphics::present(void *screenshotCallbackdata)
if (!isActive()) if (!isActive())
return; return;
if (isRenderTargetActive())
throw love::Exception("present cannot be called while a render target is active.");
deprecations.draw(this);
submitGpuCommands(true); submitGpuCommands(true);
VkPresentInfoKHR presentInfo{}; VkPresentInfoKHR presentInfo{};
@@ -266,6 +271,13 @@ void Graphics::present(void *screenshotCallbackdata)
else if (result != VK_SUCCESS) else if (result != VK_SUCCESS)
throw love::Exception("failed to present swap chain image"); throw love::Exception("failed to present swap chain image");
drawCalls = 0;
renderTargetSwitchCount = 0;
drawCallsBatched = 0;
updatePendingReadbacks();
updateTemporaryResources();
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
beginFrame(); beginFrame();
@@ -720,7 +732,7 @@ bool Graphics::dispatch(int x, int y, int z)
vkCmdBindPipeline(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_COMPUTE, computeShader->getComputePipeline()); vkCmdBindPipeline(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_COMPUTE, computeShader->getComputePipeline());
computeShader->cmdPushDescriptorSets(commandBuffers.at(currentFrame), currentFrame, VK_PIPELINE_BIND_POINT_COMPUTE); computeShader->cmdPushDescriptorSets(commandBuffers.at(currentFrame), static_cast<uint32_t>(currentFrame), VK_PIPELINE_BIND_POINT_COMPUTE);
vkCmdDispatch(commandBuffers.at(currentFrame), static_cast<uint32_t>(x), static_cast<uint32_t>(y), static_cast<uint32_t>(z)); vkCmdDispatch(commandBuffers.at(currentFrame), static_cast<uint32_t>(x), static_cast<uint32_t>(y), static_cast<uint32_t>(z));
@@ -1475,8 +1487,8 @@ VkPresentModeKHR Graphics::chooseSwapPresentMode(const std::vector<VkPresentMode
{ {
int vsync = Vulkan::getVsync(); int vsync = Vulkan::getVsync();
auto begin = availablePresentModes.begin(); const auto begin = availablePresentModes.begin();
auto end = availablePresentModes.end(); const auto end = availablePresentModes.end();
switch (vsync) { switch (vsync) {
case -1: case -1:
+12 -6
View File
@@ -217,7 +217,7 @@ void Shader::unloadVolatile()
descriptorSetsVector.clear(); descriptorSetsVector.clear();
} }
const std::vector<VkPipelineShaderStageCreateInfo>& Shader::getShaderStages() const const std::vector<VkPipelineShaderStageCreateInfo> &Shader::getShaderStages() const
{ {
return shaderStages; return shaderStages;
} }
@@ -232,7 +232,7 @@ VkPipeline Shader::getComputePipeline() const
return computePipeline; return computePipeline;
} }
static VkDescriptorImageInfo* createDescriptorImageInfo(graphics::Texture* texture, bool sampler) static VkDescriptorImageInfo* createDescriptorImageInfo(graphics::Texture *texture, bool sampler)
{ {
auto vkTexture = (Texture*)texture; auto vkTexture = (Texture*)texture;
@@ -409,13 +409,13 @@ void Shader::attach()
vgfx->setComputeShader(this); vgfx->setComputeShader(this);
} }
int Shader::getVertexAttributeIndex(const std::string& name) int Shader::getVertexAttributeIndex(const std::string &name)
{ {
auto it = attributes.find(name); auto it = attributes.find(name);
return it == attributes.end() ? -1 : it->second; return it == attributes.end() ? -1 : it->second;
} }
const Shader::UniformInfo* Shader::getUniformInfo(const std::string& name) const const Shader::UniformInfo* Shader::getUniformInfo(const std::string &name) const
{ {
return &uniformInfos.at(name); return &uniformInfos.at(name);
} }
@@ -425,7 +425,13 @@ const Shader::UniformInfo* Shader::getUniformInfo(BuiltinUniform builtin) const
return builtinUniformInfo[builtin]; return builtinUniformInfo[builtin];
} }
void Shader::sendTextures(const UniformInfo* info, graphics::Texture** textures, int count) void Shader::updateUniform(const UniformInfo* info, int count)
{
if (current == this)
Graphics::flushBatchedDrawsGlobal();
}
void Shader::sendTextures(const UniformInfo *info, graphics::Texture **textures, int count)
{ {
for (unsigned i = 0; i < count; i++) for (unsigned i = 0; i < count; i++)
{ {
@@ -447,7 +453,7 @@ void Shader::calculateUniformBufferSizeAligned()
uniformBufferSizeAligned = factor * minAlignment; uniformBufferSizeAligned = factor * minAlignment;
} }
void Shader::buildLocalUniforms(spirv_cross::Compiler& comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename) void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename)
{ {
using namespace spirv_cross; using namespace spirv_cross;
+17 -20
View File
@@ -1,8 +1,8 @@
#pragma once #pragma once
// LÖVE // LÖVE
#include <graphics/Shader.h> #include "graphics/Shader.h"
#include <graphics/vulkan/ShaderStage.h> #include "graphics/vulkan/ShaderStage.h"
#include "Vulkan.h" #include "Vulkan.h"
// Libraries // Libraries
@@ -39,7 +39,7 @@ public:
VkPipeline getComputePipeline() const; VkPipeline getComputePipeline() const;
const std::vector<VkPipelineShaderStageCreateInfo>& getShaderStages() const; const std::vector<VkPipelineShaderStageCreateInfo> &getShaderStages() const;
const VkPipelineLayout getGraphicsPipelineLayout() const; const VkPipelineLayout getGraphicsPipelineLayout() const;
@@ -51,26 +51,23 @@ public:
std::string getWarnings() const override { return ""; } std::string getWarnings() const override { return ""; }
int getVertexAttributeIndex(const std::string& name) override; int getVertexAttributeIndex(const std::string &name) override;
const UniformInfo* getUniformInfo(const std::string& name) const override; const UniformInfo *getUniformInfo(const std::string &name) const override;
const UniformInfo* getUniformInfo(BuiltinUniform builtin) const override; const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override;
// Not needed right now, since the logic that links the values of the uniforms to the shader is done in cmdPushDescriptorSets void updateUniform(const UniformInfo *info, int count) override;
// which gets called from the vulkan::Graphics class whenever a draw call happens.
// I'll have to reevaluate the use of this function in the future though.
void updateUniform(const UniformInfo* info, int count) override {}
void sendTextures(const UniformInfo* info, graphics::Texture** textures, int count) override; void sendTextures(const UniformInfo *info, graphics::Texture **textures, int count) override;
void sendBuffers(const UniformInfo* info, love::graphics::Buffer** buffers, int count) override {} void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) override {}
bool hasUniform(const std::string& name) const override; bool hasUniform(const std::string &name) const override;
void setVideoTextures(graphics::Texture* ytexture, graphics::Texture* cbtexture, graphics::Texture* crtexture) override; void setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cbtexture, graphics::Texture *crtexture) override;
// fixme: use normal methods for this in the future. // fixme: use normal methods for this in the future.
void setUniformData(BuiltinUniformData& data); void setUniformData(BuiltinUniformData &data);
void setMainTex(graphics::Texture* texture); void setMainTex(graphics::Texture *texture);
private: private:
void calculateUniformBufferSizeAligned(); void calculateUniformBufferSizeAligned();
@@ -79,10 +76,10 @@ private:
void createPipelineLayout(); void createPipelineLayout();
void createStreamBuffers(); void createStreamBuffers();
void buildLocalUniforms( void buildLocalUniforms(
spirv_cross::Compiler& comp, spirv_cross::Compiler &comp,
const spirv_cross::SPIRType& type, const spirv_cross::SPIRType &type,
size_t baseoff, size_t baseoff,
const std::string& basename); const std::string &basename);
VkDescriptorSet allocateDescriptorSet(); VkDescriptorSet allocateDescriptorSet();
@@ -112,7 +109,7 @@ private:
bool isCompute = false; bool isCompute = false;
std::unordered_map<std::string, graphics::Shader::UniformInfo> uniformInfos; std::unordered_map<std::string, graphics::Shader::UniformInfo> uniformInfos;
UniformInfo* builtinUniformInfo[BUILTIN_MAX_ENUM]; UniformInfo *builtinUniformInfo[BUILTIN_MAX_ENUM];
std::unique_ptr<StreamBuffer> uniformBufferObjectBuffer; std::unique_ptr<StreamBuffer> uniformBufferObjectBuffer;
std::vector<uint8> localUniformStagingData; std::vector<uint8> localUniformStagingData;
+37 -8
View File
@@ -79,7 +79,11 @@ bool Texture::loadVolatile()
auto commandBuffer = vgfx->getCommandBufferForDataTransfer(); auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
if (computeWrite) if (isPixelFormatDepthStencil(format))
imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
else if (isPixelFormatDepth(format))
imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
else if (computeWrite)
imageLayout = VK_IMAGE_LAYOUT_GENERAL; imageLayout = VK_IMAGE_LAYOUT_GENERAL;
else else
imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@@ -103,7 +107,7 @@ bool Texture::loadVolatile()
sliceCount = slices.getSliceCount(); sliceCount = slices.getSliceCount();
for (int slice = 0; slice < sliceCount; slice++) for (int slice = 0; slice < sliceCount; slice++)
{ {
auto* id = slices.get(slice, mip); auto *id = slices.get(slice, mip);
if (id != nullptr) if (id != nullptr)
uploadImageData(id, mip, slice, 0, 0); uploadImageData(id, mip, slice, 0, 0);
} }
@@ -200,29 +204,54 @@ void Texture::clear()
{ {
auto commandBuffer = vgfx->getCommandBufferForDataTransfer(); auto commandBuffer = vgfx->getCommandBufferForDataTransfer();
auto clearColor = getClearValue();
VkImageSubresourceRange range{}; VkImageSubresourceRange range{};
if (isPixelFormatDepthStencil(format))
range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
else if (isPixelFormatDepth(format))
range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
else
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
range.baseMipLevel = 0; range.baseMipLevel = 0;
range.levelCount = VK_REMAINING_MIP_LEVELS; range.levelCount = VK_REMAINING_MIP_LEVELS;
range.baseArrayLayer = 0; range.baseArrayLayer = 0;
range.layerCount = VK_REMAINING_ARRAY_LAYERS; range.layerCount = VK_REMAINING_ARRAY_LAYERS;
if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) if (imageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
{ {
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
0, range.levelCount, 0, range.layerCount); 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
auto clearColor = getClearValue();
vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1, &range); vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1, &range);
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
0, range.levelCount, 0, range.layerCount); 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
}
else if (imageLayout == VK_IMAGE_LAYOUT_GENERAL)
{
auto clearColor = getClearValue();
vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &range);
} }
else else
vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &range); {
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
VkClearDepthStencilValue depthStencilColor{};
depthStencilColor.depth = 0.0f;
depthStencilColor.stencil = 0;
vkCmdClearDepthStencilImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &depthStencilColor, 1, &range);
Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageLayout,
0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS);
}
} }
VkClearColorValue Texture::getClearValue() VkClearColorValue Texture::getClearValue()
+28
View File
@@ -789,6 +789,33 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
destinationStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT; destinationStage = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
} }
else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED &&
(newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || newLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL))
{
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
}
else if ((oldLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || oldLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL) &&
newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
{
barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
sourceStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &&
(newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || newLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL))
{
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
}
else else
throw std::invalid_argument("unsupported layout transition!"); throw std::invalid_argument("unsupported layout transition!");
@@ -801,6 +828,7 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima
1, &barrier 1, &barrier
); );
} }
} // vulkan } // vulkan
} // graphics } // graphics
} // love } // love