vulkan: fix bug: incorrect uniform values

This commit is contained in:
niki
2022-09-11 04:20:45 +02:00
parent 1658c89f3d
commit 294761713f
4 changed files with 227 additions and 172 deletions
+16 -18
View File
@@ -498,8 +498,6 @@ Graphics::RendererInfo Graphics::getRendererInfo() const
ss << "Vulkan( "; ss << "Vulkan( ";
if (optionalDeviceFeatures.extendedDynamicState) if (optionalDeviceFeatures.extendedDynamicState)
ss << VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME << " "; ss << VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME << " ";
if (optionalDeviceFeatures.pushDescriptor)
ss << VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME << " ";
ss << ")"; ss << ")";
info.name = ss.str(); info.name = ss.str();
@@ -732,7 +730,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), static_cast<uint32_t>(currentFrame), VK_PIPELINE_BIND_POINT_COMPUTE); computeShader->cmdPushDescriptorSets(commandBuffers.at(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));
@@ -836,6 +834,8 @@ void Graphics::beginFrame()
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
Vulkan::resetShaderSwitches(); Vulkan::resetShaderSwitches();
usedShadersInFrame.clear();
} }
void Graphics::startRecordingGraphicsCommands(bool newFrame) void Graphics::startRecordingGraphicsCommands(bool newFrame)
@@ -883,6 +883,11 @@ uint32_t Graphics::getNumImagesInFlight() const
return MAX_FRAMES_IN_FLIGHT; return MAX_FRAMES_IN_FLIGHT;
} }
uint32_t Graphics::getFrameIndex() const
{
return currentFrame;
}
const VkDeviceSize Graphics::getMinUniformBufferOffsetAlignment() const const VkDeviceSize Graphics::getMinUniformBufferOffsetAlignment() const
{ {
return minUniformBufferOffsetAlignment; return minUniformBufferOffsetAlignment;
@@ -1189,8 +1194,6 @@ static void findOptionalDeviceExtensions(VkPhysicalDevice physicalDevice, Option
{ {
if (strcmp(extension.extensionName, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) == 0) if (strcmp(extension.extensionName, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) == 0)
optionalDeviceFeatures.extendedDynamicState = true; optionalDeviceFeatures.extendedDynamicState = true;
if (strcmp(extension.extensionName, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME) == 0)
optionalDeviceFeatures.pushDescriptor = true;
} }
} }
@@ -1231,8 +1234,6 @@ void Graphics::createLogicalDevice()
if (optionalDeviceFeatures.extendedDynamicState) if (optionalDeviceFeatures.extendedDynamicState)
enabledExtensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); enabledExtensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
if (optionalDeviceFeatures.pushDescriptor)
enabledExtensions.push_back(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
createInfo.enabledExtensionCount = static_cast<uint32_t>(enabledExtensions.size()); createInfo.enabledExtensionCount = static_cast<uint32_t>(enabledExtensions.size());
createInfo.ppEnabledExtensionNames = enabledExtensions.data(); createInfo.ppEnabledExtensionNames = enabledExtensions.data();
@@ -1288,14 +1289,6 @@ void Graphics::createLogicalDevice()
ext.vkCmdSetStencilOpEXT = (PFN_vkCmdSetStencilOpEXT)vkGetDeviceProcAddr(device, "vkCmdSetStencilOpEXT"); ext.vkCmdSetStencilOpEXT = (PFN_vkCmdSetStencilOpEXT)vkGetDeviceProcAddr(device, "vkCmdSetStencilOpEXT");
ext.vkCmdSetStencilTestEnableEXT = (PFN_vkCmdSetStencilTestEnableEXT)vkGetDeviceProcAddr(device, "vkCmdSetStencilTestEnableEXT"); ext.vkCmdSetStencilTestEnableEXT = (PFN_vkCmdSetStencilTestEnableEXT)vkGetDeviceProcAddr(device, "vkCmdSetStencilTestEnableEXT");
ext.vkCmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT)vkGetDeviceProcAddr(device, "vkCmdSetViewportWithCountEXT"); ext.vkCmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT)vkGetDeviceProcAddr(device, "vkCmdSetViewportWithCountEXT");
#endif
}
if (optionalDeviceFeatures.pushDescriptor)
{
#ifdef LOVE_ANDROID
ext.vkCmdPushDescriptorSetKHR = vkCmdPushDescriptorSetKHR;
#else
ext.vkCmdPushDescriptorSetKHR = (PFN_vkCmdPushDescriptorSetKHR)vkGetDeviceProcAddr(device, "vkCmdPushDescriptorSetKHR");
#endif #endif
} }
} }
@@ -1852,6 +1845,8 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi
if (!renderPassState.active) if (!renderPassState.active)
startRenderPass(); startRenderPass();
Shader::current->attach();
GraphicsPipelineConfiguration configuration{}; GraphicsPipelineConfiguration configuration{};
configuration.renderPass = renderPassState.renderPass; configuration.renderPass = renderPassState.renderPass;
@@ -1892,8 +1887,6 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi
offsets.push_back((VkDeviceSize)0); offsets.push_back((VkDeviceSize)0);
} }
auto currentUniformData = getCurrentBuiltinUniformData();
configuration.shader->setUniformData(currentUniformData);
if (texture == nullptr) if (texture == nullptr)
configuration.shader->setMainTex(standardTexture.get()); configuration.shader->setMainTex(standardTexture.get());
else else
@@ -1901,7 +1894,7 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi
ensureGraphicsPipelineConfiguration(configuration); ensureGraphicsPipelineConfiguration(configuration);
configuration.shader->cmdPushDescriptorSets(commandBuffers.at(currentFrame), static_cast<uint32_t>(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS); configuration.shader->cmdPushDescriptorSets(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS);
vkCmdBindVertexBuffers(commandBuffers.at(currentFrame), 0, static_cast<uint32_t>(bufferVector.size()), bufferVector.data(), offsets.data()); vkCmdBindVertexBuffers(commandBuffers.at(currentFrame), 0, static_cast<uint32_t>(bufferVector.size()), bufferVector.data(), offsets.data());
} }
@@ -2074,6 +2067,11 @@ void Graphics::setComputeShader(Shader *shader)
computeShader = shader; computeShader = shader;
} }
std::set<Shader*> &Graphics::getUsedShadersInFrame()
{
return usedShadersInFrame;
}
const OptionalDeviceFeatures &Graphics::getOptionalDeviceFeatures() const const OptionalDeviceFeatures &Graphics::getOptionalDeviceFeatures() const
{ {
return optionalDeviceFeatures; return optionalDeviceFeatures;
+14 -12
View File
@@ -17,6 +17,7 @@
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <functional> #include <functional>
#include <set>
namespace love namespace love
@@ -99,7 +100,6 @@ struct OptionalInstanceExtensions
struct OptionalDeviceFeatures struct OptionalDeviceFeatures
{ {
bool extendedDynamicState = false; bool extendedDynamicState = false;
bool pushDescriptor = false;
}; };
struct OptionalDeviceExtensionFunctions struct OptionalDeviceExtensionFunctions
@@ -116,9 +116,6 @@ struct OptionalDeviceExtensionFunctions
PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT = nullptr; PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT = nullptr;
PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT = nullptr; PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT = nullptr;
PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT = nullptr; PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT = nullptr;
// push descriptor
PFN_vkCmdPushDescriptorSetKHR vkCmdPushDescriptorSetKHR = nullptr;
}; };
struct GraphicsPipelineConfiguration struct GraphicsPipelineConfiguration
@@ -232,7 +229,7 @@ public:
virtual ~Graphics(); virtual ~Graphics();
const char* getName() const override; const char *getName() const override;
const VkDevice getDevice() const; const VkDevice getDevice() const;
const VkPhysicalDevice getPhysicalDevice() const; const VkPhysicalDevice getPhysicalDevice() const;
const VmaAllocator getVmaAllocator() const; const VmaAllocator getVmaAllocator() const;
@@ -281,15 +278,20 @@ public:
void submitGpuCommands(bool present); void submitGpuCommands(bool present);
uint32_t getNumImagesInFlight() const; uint32_t getNumImagesInFlight() const;
uint32_t getFrameIndex() const;
const VkDeviceSize getMinUniformBufferOffsetAlignment() const; const VkDeviceSize getMinUniformBufferOffsetAlignment() const;
graphics::Texture *getDefaultTexture() const; graphics::Texture *getDefaultTexture() const;
VkSampler getCachedSampler(const SamplerState&); VkSampler getCachedSampler(const SamplerState&);
void setComputeShader(Shader*); void setComputeShader(Shader*);
std::set<Shader*> &getUsedShadersInFrame();
const OptionalDeviceFeatures &getOptionalDeviceFeatures() const; const OptionalDeviceFeatures &getOptionalDeviceFeatures() const;
const OptionalDeviceExtensionFunctions &getExtensionFunctions() const; const OptionalDeviceExtensionFunctions &getExtensionFunctions() const;
graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData();
protected: protected:
graphics::ShaderStage *newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles) override; graphics::ShaderStage *newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles) override;
graphics::Shader *newShaderInternal(StrongRef<love::graphics::ShaderStage> stages[SHADERSTAGE_MAX_ENUM]) override; graphics::Shader *newShaderInternal(StrongRef<love::graphics::ShaderStage> stages[SHADERSTAGE_MAX_ENUM]) override;
@@ -319,11 +321,11 @@ private:
void createImageViews(); void createImageViews();
void createDefaultRenderPass(); void createDefaultRenderPass();
void createDefaultFramebuffers(); void createDefaultFramebuffers();
VkFramebuffer createFramebuffer(FramebufferConfiguration&); VkFramebuffer createFramebuffer(FramebufferConfiguration &);
VkFramebuffer getFramebuffer(FramebufferConfiguration&); VkFramebuffer getFramebuffer(FramebufferConfiguration &);
void createDefaultShaders(); void createDefaultShaders();
VkRenderPass createRenderPass(RenderPassConfiguration&); VkRenderPass createRenderPass(RenderPassConfiguration &);
VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration&); VkPipeline createGraphicsPipeline(GraphicsPipelineConfiguration &);
void createColorResources(); void createColorResources();
VkFormat findSupportedFormat(const std::vector<VkFormat> &candidates, VkImageTiling tiling, VkFormatFeatureFlags features); VkFormat findSupportedFormat(const std::vector<VkFormat> &candidates, VkImageTiling tiling, VkFormatFeatureFlags features);
VkFormat findDepthFormat(); VkFormat findDepthFormat();
@@ -339,10 +341,9 @@ private:
void beginFrame(); void beginFrame();
void startRecordingGraphicsCommands(bool newFrame); void startRecordingGraphicsCommands(bool newFrame);
void endRecordingGraphicsCommands(bool present); void endRecordingGraphicsCommands(bool present);
void ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration&); void ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration &);
graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData();
void updatedBatchedDrawBuffers(); void updatedBatchedDrawBuffers();
bool usesConstantVertexColor(const VertexAttributes&); bool usesConstantVertexColor(const VertexAttributes &);
void createVulkanVertexFormat( void createVulkanVertexFormat(
VertexAttributes vertexAttributes, VertexAttributes vertexAttributes,
std::vector<VkVertexInputBindingDescription> &bindingDescriptions, std::vector<VkVertexInputBindingDescription> &bindingDescriptions,
@@ -405,6 +406,7 @@ private:
// just like batchedDrawBuffers we need a vector for each frame in flight. // just like batchedDrawBuffers we need a vector for each frame in flight.
std::vector<std::vector<std::function<void()>>> cleanUpFunctions; std::vector<std::vector<std::function<void()>>> cleanUpFunctions;
std::vector<std::vector<std::function<void()>>> readbackCallbacks; std::vector<std::vector<std::function<void()>>> readbackCallbacks;
std::set<Shader*> usedShadersInFrame;
RenderpassState renderPassState; RenderpassState renderPassState;
}; };
+189 -135
View File
@@ -160,8 +160,6 @@ Shader::Shader(StrongRef<love::graphics::ShaderStage> stages[])
auto gfx = Module::getInstance<Graphics>(Module::ModuleType::M_GRAPHICS); auto gfx = Module::getInstance<Graphics>(Module::ModuleType::M_GRAPHICS);
vgfx = dynamic_cast<Graphics*>(gfx); vgfx = dynamic_cast<Graphics*>(gfx);
auto &optionalDeviceFeaures = vgfx->getOptionalDeviceFeatures(); auto &optionalDeviceFeaures = vgfx->getOptionalDeviceFeatures();
if (optionalDeviceFeaures.pushDescriptor)
pfn_vkCmdPushDescriptorSetKHR = vgfx->getExtensionFunctions().vkCmdPushDescriptorSetKHR;
loadVolatile(); loadVolatile();
} }
@@ -232,7 +230,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;
@@ -246,90 +244,38 @@ static VkDescriptorImageInfo* createDescriptorImageInfo(graphics::Texture *textu
return imageInfo; return imageInfo;
} }
void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frameIndex, VkPipelineBindPoint bindPoint) void Shader::newFrame(uint32_t frameIndex)
{ {
// detect whether a new frame has begun currentFrame = frameIndex;
if (currentFrame != frameIndex)
currentUsedUniformStreamBuffersCount = 0;
currentUsedDescriptorSetsCount = 0;
if (streamBuffers.at(currentFrame).size() > 1)
{ {
currentFrame = frameIndex; size_t newSize = 0;
for (auto streamBuffer : streamBuffers.at(currentFrame))
currentUsedUniformStreamBuffersCount = 0;
currentUsedDescriptorSetsCount = 0;
// we needed more memory last frame, let's collapse all buffers into a single one.
if (streamBuffers.at(currentFrame).size() > 1)
{ {
size_t newSize = 0; newSize += streamBuffer->getSize();
for (auto streamBuffer : streamBuffers.at(currentFrame)) delete streamBuffer;
{
newSize += streamBuffer->getSize();
delete streamBuffer;
}
streamBuffers.at(currentFrame).clear();
streamBuffers.at(currentFrame).push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, newSize));
} }
// no collapse necessary, can just call nextFrame to reset the current (only) streambuffer streamBuffers.at(currentFrame).clear();
else streamBuffers.at(currentFrame).push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, newSize));
streamBuffers.at(currentFrame).at(0)->nextFrame();
} }
// still the same frame
else else
{ streamBuffers.at(currentFrame).at(0)->nextFrame();
auto usedStreamBufferMemory = currentUsedUniformStreamBuffersCount * uniformBufferSizeAligned;
if (usedStreamBufferMemory >= streamBuffers.at(currentFrame).back()->getSize())
{
// we ran out of memory in the current frame, need to allocate more.
streamBuffers.at(currentFrame).push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned));
currentUsedUniformStreamBuffersCount = 0;
}
}
VkDescriptorSet currentDescriptorSet; if (currentUsedDescriptorSetsCount >= static_cast<uint32_t>(descriptorSetsVector.at(currentFrame).size()))
descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet());
if (pfn_vkCmdPushDescriptorSetKHR) currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount);
currentDescriptorSet = 0;
else
{
if (currentUsedDescriptorSetsCount >= static_cast<uint32_t>(descriptorSetsVector.at(currentFrame).size()))
descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet());
currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount);
}
std::vector<VkWriteDescriptorSet> descriptorWrite{}; std::vector<VkWriteDescriptorSet> descriptorWrite{};
VkDescriptorBufferInfo* bufferInfo = nullptr;
if (!localUniformStagingData.empty()) {
// additional data is always added onto the last stream buffer in the current frame
auto currentStreamBuffer = streamBuffers.at(currentFrame).back();
auto mapInfo = currentStreamBuffer->map(uniformBufferSizeAligned);
memcpy(mapInfo.data, localUniformStagingData.data(), localUniformStagingData.size());
currentStreamBuffer->unmap(uniformBufferSizeAligned);
currentStreamBuffer->markUsed(uniformBufferSizeAligned);
bufferInfo = new VkDescriptorBufferInfo();
bufferInfo->buffer = (VkBuffer)currentStreamBuffer->getHandle();
bufferInfo->offset = currentUsedUniformStreamBuffersCount * uniformBufferSizeAligned;
bufferInfo->range = localUniformStagingData.size();
VkWriteDescriptorSet uniformWrite{};
uniformWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
uniformWrite.dstSet = currentDescriptorSet;
uniformWrite.dstBinding = uniformLocation;
uniformWrite.dstArrayElement = 0;
uniformWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
uniformWrite.descriptorCount = 1;
uniformWrite.pBufferInfo = bufferInfo;
descriptorWrite.push_back(uniformWrite);
}
std::vector<VkDescriptorImageInfo*> imageInfos; std::vector<VkDescriptorImageInfo*> imageInfos;
// update everything other than uniform buffers (since that's already taken care of. // update everything other than uniform buffers
for (const auto& [key, val] : uniformInfos) { for (const auto &[key, val] : uniformInfos) {
// fixme: other types. // fixme: other types.
if (val.baseType == UNIFORM_SAMPLER) { if (val.baseType == UNIFORM_SAMPLER) {
VkWriteDescriptorSet write{}; VkWriteDescriptorSet write{};
@@ -364,29 +310,93 @@ void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frame
} }
} }
if (pfn_vkCmdPushDescriptorSetKHR) vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrite.size()), descriptorWrite.data(), 0, nullptr);
pfn_vkCmdPushDescriptorSetKHR(
commandBuffer,
bindPoint,
pipelineLayout,
0,
static_cast<uint32_t>(descriptorWrite.size()),
descriptorWrite.data());
else
{
vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrite.size()), descriptorWrite.data(), 0, nullptr);
vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, &currentDescriptorSet, 0, nullptr);
currentUsedDescriptorSetsCount++;
}
for (const auto imageInfo : imageInfos) for (const auto imageInfo : imageInfos)
delete imageInfo; delete imageInfo;
if (bufferInfo) }
delete bufferInfo;
currentUsedUniformStreamBuffersCount++; void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint bindPoint)
{
if (!localUniformData.empty())
{
auto usedStreamBufferMemory = currentUsedUniformStreamBuffersCount * uniformBufferSizeAligned;
if (usedStreamBufferMemory >= streamBuffers.at(currentFrame).back()->getSize())
{
streamBuffers.at(currentFrame).push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned));
currentUsedUniformStreamBuffersCount = 0;
}
if (builtinUniformDataOffset.has_value())
{
auto builtinData = vgfx->getCurrentBuiltinUniformData();
auto dst = localUniformData.data() + builtinUniformDataOffset.value();
memcpy(dst, &builtinData, sizeof(builtinData));
}
// additional data is always added onto the last stream buffer in the current frame
auto currentStreamBuffer = streamBuffers.at(currentFrame).back();
auto mapInfo = currentStreamBuffer->map(uniformBufferSizeAligned);
memcpy(mapInfo.data, localUniformData.data(), localUniformData.size());
currentStreamBuffer->unmap(uniformBufferSizeAligned);
currentStreamBuffer->markUsed(uniformBufferSizeAligned);
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = (VkBuffer)currentStreamBuffer->getHandle();
bufferInfo.offset = currentUsedUniformStreamBuffersCount * uniformBufferSizeAligned;
bufferInfo.range = localUniformData.size();
VkWriteDescriptorSet uniformWrite{};
uniformWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
uniformWrite.dstSet = currentDescriptorSet;
uniformWrite.dstBinding = uniformLocation;
uniformWrite.dstArrayElement = 0;
uniformWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
uniformWrite.descriptorCount = 1;
uniformWrite.pBufferInfo = &bufferInfo;
vkUpdateDescriptorSets(device, 1, &uniformWrite, 0, nullptr);
currentUsedUniformStreamBuffersCount++;
}
static const std::vector<BuiltinUniform> builtinUniformTextures = {
BUILTIN_TEXTURE_MAIN,
BUILTIN_TEXTURE_VIDEO_Y,
BUILTIN_TEXTURE_VIDEO_CB,
BUILTIN_TEXTURE_VIDEO_CR,
};
for (const auto &builtin : builtinUniformTextures)
if (builtinUniformInfo[builtin] != nullptr)
{
auto texture = dynamic_cast<Texture*>(builtinUniformInfo[builtin]->textures[0]);
VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = texture->getImageLayout();
imageInfo.imageView = (VkImageView)texture->getRenderTargetHandle();
imageInfo.sampler = (VkSampler)texture->getSamplerHandle();
VkWriteDescriptorSet mainTexWrite{};
mainTexWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
mainTexWrite.dstSet = currentDescriptorSet;
mainTexWrite.dstBinding = builtinUniformInfo[builtin]->location;
mainTexWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
mainTexWrite.descriptorCount = 1;
mainTexWrite.pImageInfo = &imageInfo;
vkUpdateDescriptorSets(device, 1, &mainTexWrite, 0, nullptr);
}
vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, &currentDescriptorSet, 0, nullptr);
currentUsedDescriptorSetsCount++;
if (currentUsedDescriptorSetsCount >= static_cast<uint32_t>(descriptorSetsVector.at(currentFrame).size()))
descriptorSetsVector.at(currentFrame).push_back(allocateDescriptorSet());
currentDescriptorSet = descriptorSetsVector.at(currentFrame).at(currentUsedDescriptorSetsCount);
} }
Shader::~Shader() Shader::~Shader()
@@ -396,6 +406,13 @@ Shader::~Shader()
void Shader::attach() void Shader::attach()
{ {
auto &usedShadersInFrame = vgfx->getUsedShadersInFrame();
if (usedShadersInFrame.find(this) == usedShadersInFrame.end())
{
newFrame(vgfx->getFrameIndex());
usedShadersInFrame.insert(this);
}
if (!isCompute) if (!isCompute)
{ {
if (Shader::current != this) if (Shader::current != this)
@@ -415,25 +432,68 @@ int Shader::getVertexAttributeIndex(const std::string &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);
} }
const Shader::UniformInfo* Shader::getUniformInfo(BuiltinUniform builtin) const const Shader::UniformInfo *Shader::getUniformInfo(BuiltinUniform builtin) const
{ {
return builtinUniformInfo[builtin]; return builtinUniformInfo[builtin];
} }
void Shader::updateUniform(const UniformInfo* info, int count) static bool usesLocalUniformData(const graphics::Shader::UniformInfo *info)
{
return info->baseType == graphics::Shader::UNIFORM_BOOL ||
info->baseType == graphics::Shader::UNIFORM_FLOAT ||
info->baseType == graphics::Shader::UNIFORM_INT ||
info->baseType == graphics::Shader::UNIFORM_MATRIX ||
info->baseType == graphics::Shader::UNIFORM_UINT;
}
void Shader::updateUniform(const UniformInfo *info, int count)
{ {
if (current == this) if (current == this)
Graphics::flushBatchedDrawsGlobal(); Graphics::flushBatchedDrawsGlobal();
if (usesLocalUniformData(info))
memcpy(localUniformData.data(), localUniformStagingData.data(), localUniformStagingData.size());
else if (info->baseType == UNIFORM_SAMPLER || info->baseType == UNIFORM_STORAGETEXTURE)
{
bool isSampler = info->baseType == UNIFORM_SAMPLER;
std::vector<VkDescriptorImageInfo> imageInfos;
for (int i = 0; i < count; i++)
{
auto vkTexture = dynamic_cast<Texture*>(info->textures[i]);
VkDescriptorImageInfo imageInfo{};
imageInfo.imageLayout = vkTexture->getImageLayout();
imageInfo.imageView = (VkImageView)vkTexture->getRenderTargetHandle();
if (isSampler)
imageInfo.sampler = (VkSampler)vkTexture->getSamplerHandle();
imageInfos.push_back(imageInfo);
}
VkWriteDescriptorSet write{};
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write.dstSet = currentDescriptorSet;
write.dstBinding = info->location;
write.dstArrayElement = 0;
write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write.descriptorCount = static_cast<uint32_t>(count);
write.pImageInfo = imageInfos.data();
vkUpdateDescriptorSets(device, 1, &write, 0, nullptr);
}
} }
void Shader::sendTextures(const UniformInfo *info, graphics::Texture **textures, int count) void Shader::sendTextures(const UniformInfo *info, graphics::Texture **textures, int count)
{ {
for (unsigned i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
auto oldTexture = info->textures[i]; auto oldTexture = info->textures[i];
info->textures[i] = textures[i]; info->textures[i] = textures[i];
@@ -457,11 +517,11 @@ void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::
{ {
using namespace spirv_cross; using namespace spirv_cross;
const auto& membertypes = type.member_types; const auto &membertypes = type.member_types;
for (size_t uindex = 0; uindex < membertypes.size(); uindex++) for (size_t uindex = 0; uindex < membertypes.size(); uindex++)
{ {
const auto& memberType = comp.get_type(membertypes[uindex]); const auto &memberType = comp.get_type(membertypes[uindex]);
size_t memberSize = comp.get_declared_struct_member_size(type, uindex); size_t memberSize = comp.get_declared_struct_member_size(type, uindex);
size_t offset = baseoff + comp.type_struct_member_offset(type, uindex); size_t offset = baseoff + comp.type_struct_member_offset(type, uindex);
@@ -505,11 +565,11 @@ void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::
u.matrix.columns = memberType.columns; u.matrix.columns = memberType.columns;
} }
const auto& reflectionIt = validationReflection.localUniforms.find(u.name); const auto &reflectionIt = validationReflection.localUniforms.find(u.name);
if (reflectionIt != validationReflection.localUniforms.end()) if (reflectionIt != validationReflection.localUniforms.end())
{ {
const auto& localUniform = reflectionIt->second; const auto &localUniform = reflectionIt->second;
const auto& values = localUniform.initializerValues; const auto &values = localUniform.initializerValues;
if (!values.empty()) if (!values.empty())
memcpy( memcpy(
u.data, u.data,
@@ -562,8 +622,8 @@ void Shader::compileShaders()
tshader->setGlobalUniformBinding(0); tshader->setGlobalUniformBinding(0);
tshader->setGlobalUniformSet(0); tshader->setGlobalUniformSet(0);
auto& glsl = stages[i]->getSource(); auto &glsl = stages[i]->getSource();
const char* csrc = glsl.c_str(); const char *csrc = glsl.c_str();
const int sourceLength = static_cast<int>(glsl.length()); const int sourceLength = static_cast<int>(glsl.length());
tshader->setStringsWithLengths(&csrc, &sourceLength, 1); tshader->setStringsWithLengths(&csrc, &sourceLength, 1);
@@ -574,8 +634,8 @@ void Shader::compileShaders()
if (!tshader->parse(&defaultTBuiltInResource, defaultVersion, defaultProfile, forceDefault, forwardCompat, EShMsgSuppressWarnings)) if (!tshader->parse(&defaultTBuiltInResource, defaultVersion, defaultProfile, forceDefault, forwardCompat, EShMsgSuppressWarnings))
{ {
const char* msg1 = tshader->getInfoLog(); const char *msg1 = tshader->getInfoLog();
const char* msg2 = tshader->getInfoDebugLog(); const char *msg2 = tshader->getInfoDebugLog();
throw love::Exception("error while parsing shader"); throw love::Exception("error while parsing shader");
} }
@@ -640,7 +700,7 @@ void Shader::compileShaders()
auto shaderResources = comp.get_shader_resources(active); auto shaderResources = comp.get_shader_resources(active);
comp.set_enabled_interface_variables(std::move(active)); comp.set_enabled_interface_variables(std::move(active));
for (const auto& resource : shaderResources.uniform_buffers) for (const auto &resource : shaderResources.uniform_buffers)
{ {
if (resource.name == "gl_DefaultUniformBlock") if (resource.name == "gl_DefaultUniformBlock")
{ {
@@ -648,22 +708,26 @@ void Shader::compileShaders()
size_t uniformBufferObjectSize = comp.get_declared_struct_size(type); size_t uniformBufferObjectSize = comp.get_declared_struct_size(type);
auto defaultUniformBlockSize = comp.get_declared_struct_size(type); auto defaultUniformBlockSize = comp.get_declared_struct_size(type);
localUniformStagingData.resize(defaultUniformBlockSize); localUniformStagingData.resize(defaultUniformBlockSize);
localUniformData.resize(defaultUniformBlockSize);
uniformLocation = comp.get_decoration(resource.id, spv::DecorationBinding); uniformLocation = comp.get_decoration(resource.id, spv::DecorationBinding);
memset(localUniformStagingData.data(), 0, defaultUniformBlockSize); memset(localUniformStagingData.data(), 0, defaultUniformBlockSize);
memset(localUniformData.data(), 0, defaultUniformBlockSize);
std::string basename(""); std::string basename("");
buildLocalUniforms(comp, type, 0, basename); buildLocalUniforms(comp, type, 0, basename);
memcpy(localUniformData.data(), localUniformStagingData.data(), localUniformStagingData.size());
} }
else else
throw love::Exception("unimplemented: non default uniform blocks."); throw love::Exception("unimplemented: non default uniform blocks.");
} }
for (const auto& r : shaderResources.sampled_images) for (const auto &r : shaderResources.sampled_images)
{ {
const SPIRType& basetype = comp.get_type(r.base_type_id); const SPIRType &basetype = comp.get_type(r.base_type_id);
const SPIRType& type = comp.get_type(r.type_id); const SPIRType &type = comp.get_type(r.type_id);
const SPIRType& imagetype = comp.get_type(basetype.image.type); const SPIRType &imagetype = comp.get_type(basetype.image.type);
graphics::Shader::UniformInfo info; graphics::Shader::UniformInfo info;
info.location = comp.get_decoration(r.id, spv::DecorationBinding); info.location = comp.get_decoration(r.id, spv::DecorationBinding);
@@ -729,9 +793,9 @@ void Shader::compileShaders()
builtinUniformInfo[builtin] = &uniformInfos[info.name]; builtinUniformInfo[builtin] = &uniformInfos[info.name];
} }
for (const auto& r : shaderResources.storage_buffers) for (const auto &r : shaderResources.storage_buffers)
{ {
const auto& type = comp.get_type(r.type_id); const auto &type = comp.get_type(r.type_id);
UniformInfo u{}; UniformInfo u{};
u.baseType = UNIFORM_STORAGEBUFFER; u.baseType = UNIFORM_STORAGEBUFFER;
@@ -752,7 +816,7 @@ void Shader::compileShaders()
// todo: some stuff missing // todo: some stuff missing
u.buffers = new love::graphics::Buffer * [u.count]; u.buffers = new love::graphics::Buffer *[u.count];
for (int i = 0; i < u.count; i++) for (int i = 0; i < u.count; i++)
u.buffers[i] = nullptr; u.buffers[i] = nullptr;
@@ -760,16 +824,16 @@ void Shader::compileShaders()
uniformInfos[u.name] = u; uniformInfos[u.name] = u;
} }
for (const auto& r : shaderResources.storage_images) for (const auto &r : shaderResources.storage_images)
{ {
const auto& type = comp.get_type(r.type_id); const auto &type = comp.get_type(r.type_id);
UniformInfo u{}; UniformInfo u{};
u.baseType = UNIFORM_STORAGETEXTURE; u.baseType = UNIFORM_STORAGETEXTURE;
u.components = 1; u.components = 1;
u.name = r.name; u.name = r.name;
u.count = type.array.empty() ? 1 : type.array[0]; u.count = type.array.empty() ? 1 : type.array[0];
u.textures = new love::graphics::Texture * [u.count]; u.textures = new love::graphics::Texture *[u.count];
u.location = comp.get_decoration(r.id, spv::DecorationBinding); u.location = comp.get_decoration(r.id, spv::DecorationBinding);
for (int i = 0; i < u.count; i++) for (int i = 0; i < u.count; i++)
@@ -781,9 +845,9 @@ void Shader::compileShaders()
} }
if (shaderStage == SHADERSTAGE_VERTEX) if (shaderStage == SHADERSTAGE_VERTEX)
for (const auto& r : shaderResources.stage_inputs) for (const auto &r : shaderResources.stage_inputs)
{ {
const auto& name = r.name; const auto &name = r.name;
const int attributeLocation = static_cast<int>(comp.get_decoration(r.id, spv::DecorationLocation)); const int attributeLocation = static_cast<int>(comp.get_decoration(r.id, spv::DecorationLocation));
attributes[name] = attributeLocation; attributes[name] = attributeLocation;
} }
@@ -798,7 +862,7 @@ void Shader::createDescriptorSetLayout()
{ {
std::vector<VkDescriptorSetLayoutBinding> bindings; std::vector<VkDescriptorSetLayoutBinding> bindings;
for (auto const& [key, val] : uniformInfos) for (auto const &[key, val] : uniformInfos)
{ {
auto type = Vulkan::getDescriptorType(val.baseType); auto type = Vulkan::getDescriptorType(val.baseType);
if (type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) if (type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
@@ -834,8 +898,6 @@ void Shader::createDescriptorSetLayout()
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size()); layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
layoutInfo.pBindings = bindings.data(); layoutInfo.pBindings = bindings.data();
if (pfn_vkCmdPushDescriptorSetKHR)
layoutInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS)
throw love::Exception("failed to create descriptor set layout"); throw love::Exception("failed to create descriptor set layout");
@@ -874,7 +936,7 @@ void Shader::createStreamBuffers()
streamBuffers[i].push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned)); streamBuffers[i].push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned));
} }
void Shader::setVideoTextures(graphics::Texture* ytexture, graphics::Texture* cbtexture, graphics::Texture* crtexture) void Shader::setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cbtexture, graphics::Texture *crtexture)
{ {
// if the shader doesn't actually use these textures they might get optimized out // if the shader doesn't actually use these textures they might get optimized out
// in that case this function becomes a noop. // in that case this function becomes a noop.
@@ -901,21 +963,13 @@ void Shader::setVideoTextures(graphics::Texture* ytexture, graphics::Texture* cb
} }
} }
bool Shader::hasUniform(const std::string& name) const bool Shader::hasUniform(const std::string &name) const
{ {
return uniformInfos.find(name) != uniformInfos.end(); return uniformInfos.find(name) != uniformInfos.end();
} }
void Shader::setUniformData(BuiltinUniformData& data) void Shader::setMainTex(graphics::Texture *texture)
{ {
char* ptr = (char*) builtinUniformInfo[BUILTIN_UNIFORMS_PER_DRAW]->data + builtinUniformDataOffset;
memcpy(ptr, &data, sizeof(BuiltinUniformData));
}
void Shader::setMainTex(graphics::Texture* texture)
{
// if the shader doesn't actually use the texture it might get optimized out
// in that case this function becomes a noop.
if (builtinUniformInfo[BUILTIN_TEXTURE_MAIN] != nullptr) if (builtinUniformInfo[BUILTIN_TEXTURE_MAIN] != nullptr)
{ {
auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0]; auto oldTexture = builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0];
@@ -938,7 +992,7 @@ VkDescriptorSet Shader::allocateDescriptorSet()
sizes.push_back(size); sizes.push_back(size);
for (const auto& [key, val] : uniformInfos) for (const auto &[key, val] : uniformInfos)
{ {
VkDescriptorPoolSize size{}; VkDescriptorPoolSize size{};
auto type = Vulkan::getDescriptorType(val.baseType); auto type = Vulkan::getDescriptorType(val.baseType);
+8 -7
View File
@@ -12,9 +12,9 @@
// C++ // C++
#include <map> #include <map>
#include <memory> #include <memory>
#include <iostream>
#include <unordered_map> #include <unordered_map>
#include <queue> #include <queue>
#include <optional>
namespace love namespace love
@@ -43,7 +43,9 @@ public:
const VkPipelineLayout getGraphicsPipelineLayout() const; const VkPipelineLayout getGraphicsPipelineLayout() const;
void cmdPushDescriptorSets(VkCommandBuffer, uint32_t currentFrame, VkPipelineBindPoint); void newFrame(uint32_t frameIndex);
void cmdPushDescriptorSets(VkCommandBuffer, VkPipelineBindPoint);
void attach() override; void attach() override;
@@ -65,8 +67,6 @@ public:
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.
void setUniformData(BuiltinUniformData &data);
void setMainTex(graphics::Texture *texture); void setMainTex(graphics::Texture *texture);
private: private:
@@ -83,8 +83,6 @@ private:
VkDescriptorSet allocateDescriptorSet(); VkDescriptorSet allocateDescriptorSet();
PFN_vkCmdPushDescriptorSetKHR pfn_vkCmdPushDescriptorSetKHR = nullptr;
VkDeviceSize uniformBufferSizeAligned; VkDeviceSize uniformBufferSizeAligned;
VkPipeline computePipeline; VkPipeline computePipeline;
@@ -112,12 +110,15 @@ private:
UniformInfo *builtinUniformInfo[BUILTIN_MAX_ENUM]; UniformInfo *builtinUniformInfo[BUILTIN_MAX_ENUM];
std::unique_ptr<StreamBuffer> uniformBufferObjectBuffer; std::unique_ptr<StreamBuffer> uniformBufferObjectBuffer;
std::vector<uint8> localUniformData;
std::vector<uint8> localUniformStagingData; std::vector<uint8> localUniformStagingData;
uint32_t uniformLocation; uint32_t uniformLocation;
size_t builtinUniformDataOffset; std::optional<size_t> builtinUniformDataOffset;
std::unordered_map<std::string, int> attributes; std::unordered_map<std::string, int> attributes;
VkDescriptorSet currentDescriptorSet;
uint32_t currentFrame; uint32_t currentFrame;
uint32_t currentUsedUniformStreamBuffersCount; uint32_t currentUsedUniformStreamBuffersCount;
uint32_t currentUsedDescriptorSetsCount; uint32_t currentUsedDescriptorSetsCount;