mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
[Refactor] (MG_Backend/DirectVulkan): move uniform reflection from UniformDescriptorBinder to ProgramFactory
This commit is contained in:
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include "ProgramFactory.h"
|
#include "ProgramFactory.h"
|
||||||
|
|
||||||
|
#include "MG_Util/ShaderTranspiler/Types.h"
|
||||||
|
#include <cstring>
|
||||||
#include <spirv-tools/libspirv.h>
|
#include <spirv-tools/libspirv.h>
|
||||||
#include <spirv-tools/optimizer.hpp>
|
#include <spirv-tools/optimizer.hpp>
|
||||||
#include <source/opt/constants.h>
|
#include <source/opt/constants.h>
|
||||||
@@ -321,7 +323,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
ProgramFactory::~ProgramFactory() = default;
|
ProgramFactory::~ProgramFactory() {
|
||||||
|
DestroyLayoutCache();
|
||||||
|
}
|
||||||
|
|
||||||
VkShaderStageFlagBits ProgramFactory::ToVkStage(ShaderStage stage) {
|
VkShaderStageFlagBits ProgramFactory::ToVkStage(ShaderStage stage) {
|
||||||
switch (stage) {
|
switch (stage) {
|
||||||
@@ -355,6 +359,266 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProgramFactory::HashType ProgramFactory::ComputeLayoutHash(const MG_State::GLState::ProgramObject& program) const {
|
||||||
|
XXHASH_VERIFY(XXH64_reset(m_hashState, m_config.CacheVersion));
|
||||||
|
const auto& spirvs = program.GetGeneratedSpirv();
|
||||||
|
for (const auto& spv : spirvs) {
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, spv.data(), spv.size() * sizeof(Uint)));
|
||||||
|
}
|
||||||
|
|
||||||
|
const Uint32 blockCount = static_cast<Uint32>(program.GetActiveUniformBlocksCount());
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &blockCount, sizeof(blockCount)));
|
||||||
|
for (Uint32 i = 0; i < blockCount; ++i) {
|
||||||
|
const Uint32 binding = program.GetUniformBlockBinding(i);
|
||||||
|
XXHASH_VERIFY(XXH64_update(m_hashState, &binding, sizeof(binding)));
|
||||||
|
}
|
||||||
|
return XXH64_digest(m_hashState);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureTarget ProgramFactory::UniformTypeToTextureTarget(GLenum glType) {
|
||||||
|
switch (glType) {
|
||||||
|
case GL_SAMPLER_1D:
|
||||||
|
case GL_INT_SAMPLER_1D:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_1D:
|
||||||
|
return TextureTarget::Texture1D;
|
||||||
|
case GL_SAMPLER_3D:
|
||||||
|
case GL_INT_SAMPLER_3D:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_3D:
|
||||||
|
return TextureTarget::Texture3D;
|
||||||
|
case GL_SAMPLER_CUBE:
|
||||||
|
case GL_SAMPLER_CUBE_SHADOW:
|
||||||
|
case GL_INT_SAMPLER_CUBE:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_CUBE:
|
||||||
|
return TextureTarget::TextureCubeMap;
|
||||||
|
case GL_SAMPLER_2D_MULTISAMPLE:
|
||||||
|
case GL_INT_SAMPLER_2D_MULTISAMPLE:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
|
||||||
|
return TextureTarget::Texture2DMultisample;
|
||||||
|
case GL_SAMPLER_BUFFER:
|
||||||
|
case GL_INT_SAMPLER_BUFFER:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_BUFFER:
|
||||||
|
return TextureTarget::TextureBuffer;
|
||||||
|
case GL_SAMPLER_1D_ARRAY:
|
||||||
|
case GL_SAMPLER_1D_ARRAY_SHADOW:
|
||||||
|
case GL_INT_SAMPLER_1D_ARRAY:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
|
||||||
|
return TextureTarget::Texture1DArray;
|
||||||
|
case GL_SAMPLER_2D_ARRAY:
|
||||||
|
case GL_SAMPLER_2D_ARRAY_SHADOW:
|
||||||
|
case GL_INT_SAMPLER_2D_ARRAY:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
||||||
|
return TextureTarget::Texture2DArray;
|
||||||
|
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||||
|
case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||||
|
return TextureTarget::Texture2DMultisampleArray;
|
||||||
|
case GL_SAMPLER_2D_RECT:
|
||||||
|
case GL_SAMPLER_2D_RECT_SHADOW:
|
||||||
|
case GL_INT_SAMPLER_2D_RECT:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
|
||||||
|
return TextureTarget::TextureRectangle;
|
||||||
|
case GL_SAMPLER_2D:
|
||||||
|
case GL_SAMPLER_2D_SHADOW:
|
||||||
|
case GL_INT_SAMPLER_2D:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_2D:
|
||||||
|
default:
|
||||||
|
return TextureTarget::Texture2D;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool ProgramFactory::ReflectBindingKinds(const MG_State::GLState::ProgramObject& program,
|
||||||
|
Vector<DescriptorBindingKind>& outKinds) const {
|
||||||
|
outKinds.assign(m_maxBindings, DescriptorBindingKind::None);
|
||||||
|
|
||||||
|
const auto& spirv = program.GetGeneratedSpirv();
|
||||||
|
for (const auto& module : spirv) {
|
||||||
|
if (module.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
spvc_context context = nullptr;
|
||||||
|
spvc_parsed_ir ir = nullptr;
|
||||||
|
spvc_compiler compiler = nullptr;
|
||||||
|
spvc_resources resources = nullptr;
|
||||||
|
|
||||||
|
if (spvc_context_create(&context) != SPVC_SUCCESS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const spvc_result parseResult = spvc_context_parse_spirv(context, module.data(), module.size(), &ir);
|
||||||
|
if (parseResult != SPVC_SUCCESS) {
|
||||||
|
spvc_context_destroy(context);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const spvc_result compilerResult =
|
||||||
|
spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler);
|
||||||
|
if (compilerResult != SPVC_SUCCESS) {
|
||||||
|
spvc_context_destroy(context);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spvc_compiler_create_shader_resources(compiler, &resources) != SPVC_SUCCESS) {
|
||||||
|
spvc_context_destroy(context);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto applyBindings = [&](spvc_resource_type resourceType, DescriptorBindingKind kind) {
|
||||||
|
const spvc_reflected_resource* list = nullptr;
|
||||||
|
size_t count = 0;
|
||||||
|
if (spvc_resources_get_resource_list_for_type(resources, resourceType, &list, &count) != SPVC_SUCCESS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
const Uint32 binding =
|
||||||
|
spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding);
|
||||||
|
if (binding >= m_maxBindings) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (kind == DescriptorBindingKind::CombinedImageSampler) {
|
||||||
|
outKinds[binding] = DescriptorBindingKind::CombinedImageSampler;
|
||||||
|
} else if (outKinds[binding] == DescriptorBindingKind::None) {
|
||||||
|
outKinds[binding] = kind;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
applyBindings(SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, DescriptorBindingKind::UniformBufferDynamic);
|
||||||
|
applyBindings(SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, DescriptorBindingKind::CombinedImageSampler);
|
||||||
|
|
||||||
|
spvc_context_destroy(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool ProgramFactory::ReflectSamplerBindings(const MG_State::GLState::ProgramObject& program,
|
||||||
|
VkProgramLayout& layout) const {
|
||||||
|
layout.samplerUniformLocationByBinding.assign(m_maxBindings, -1);
|
||||||
|
layout.samplerTextureTargetByBinding.assign(m_maxBindings, TextureTarget::Texture2D);
|
||||||
|
|
||||||
|
const auto& spirv = program.GetGeneratedSpirv();
|
||||||
|
for (const auto& module : spirv) {
|
||||||
|
if (module.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
spvc_context context = nullptr;
|
||||||
|
spvc_parsed_ir ir = nullptr;
|
||||||
|
spvc_compiler compiler = nullptr;
|
||||||
|
spvc_resources resources = nullptr;
|
||||||
|
|
||||||
|
if (spvc_context_create(&context) != SPVC_SUCCESS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (spvc_context_parse_spirv(context, module.data(), module.size(), &ir) != SPVC_SUCCESS) {
|
||||||
|
spvc_context_destroy(context);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP,
|
||||||
|
&compiler) != SPVC_SUCCESS) {
|
||||||
|
spvc_context_destroy(context);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (spvc_compiler_create_shader_resources(compiler, &resources) != SPVC_SUCCESS) {
|
||||||
|
spvc_context_destroy(context);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const spvc_reflected_resource* list = nullptr;
|
||||||
|
size_t count = 0;
|
||||||
|
if (spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, &list, &count) ==
|
||||||
|
SPVC_SUCCESS) {
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
const Uint32 binding =
|
||||||
|
spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding);
|
||||||
|
if (binding >= m_maxBindings) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String uniformName = list[i].name ? list[i].name : "";
|
||||||
|
Int location = program.GetUniformLocation(uniformName);
|
||||||
|
if (location < 0) {
|
||||||
|
const auto arraySuffix = uniformName.find("[0]");
|
||||||
|
if (arraySuffix != String::npos) {
|
||||||
|
uniformName = uniformName.substr(0, arraySuffix);
|
||||||
|
location = program.GetUniformLocation(uniformName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (location < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.samplerUniformLocationByBinding[binding] = location;
|
||||||
|
layout.samplerTextureTargetByBinding[binding] =
|
||||||
|
UniformTypeToTextureTarget(program.GetUniformType(static_cast<Uint>(location)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spvc_context_destroy(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bool ProgramFactory::ReflectGlobalUboBinding(const MG_State::GLState::ProgramObject& program,
|
||||||
|
VkProgramLayout& layout) const {
|
||||||
|
layout.globalUboBinding = -1;
|
||||||
|
|
||||||
|
const auto& spirv = program.GetGeneratedSpirv();
|
||||||
|
for (const auto& module : spirv) {
|
||||||
|
if (module.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
spvc_context context = nullptr;
|
||||||
|
spvc_parsed_ir ir = nullptr;
|
||||||
|
spvc_compiler compiler = nullptr;
|
||||||
|
spvc_resources resources = nullptr;
|
||||||
|
|
||||||
|
if (spvc_context_create(&context) != SPVC_SUCCESS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (spvc_context_parse_spirv(context, module.data(), module.size(), &ir) != SPVC_SUCCESS) {
|
||||||
|
spvc_context_destroy(context);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP,
|
||||||
|
&compiler) != SPVC_SUCCESS) {
|
||||||
|
spvc_context_destroy(context);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (spvc_compiler_create_shader_resources(compiler, &resources) != SPVC_SUCCESS) {
|
||||||
|
spvc_context_destroy(context);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const spvc_reflected_resource* list = nullptr;
|
||||||
|
size_t count = 0;
|
||||||
|
if (spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &list, &count) ==
|
||||||
|
SPVC_SUCCESS) {
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
const char* name = list[i].name ? list[i].name : "";
|
||||||
|
if (std::strstr(name, MG_Util::ShaderTranspiler::GLOBAL_UBO_NAME) == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const Uint32 binding =
|
||||||
|
spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding);
|
||||||
|
if (binding < m_maxBindings) {
|
||||||
|
layout.globalUboBinding = static_cast<Int>(binding);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spvc_context_destroy(context);
|
||||||
|
if (layout.globalUboBinding >= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Vector<VkPipelineShaderStageCreateInfo>& ProgramFactory::GetOrCreatePipelineShaderStages(
|
Vector<VkPipelineShaderStageCreateInfo>& ProgramFactory::GetOrCreatePipelineShaderStages(
|
||||||
const MG_State::GLState::ProgramObject& program, CompileOptionFlags flags) {
|
const MG_State::GLState::ProgramObject& program, CompileOptionFlags flags) {
|
||||||
auto hash = ComputeHash(program, flags);
|
auto hash = ComputeHash(program, flags);
|
||||||
@@ -402,4 +666,86 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
return entry.stages;
|
return entry.stages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ProgramFactory::VkProgramLayout* ProgramFactory::GetOrCreateProgramLayout(
|
||||||
|
const MG_State::GLState::ProgramObject& program) {
|
||||||
|
const HashType hash = ComputeLayoutHash(program);
|
||||||
|
auto it = m_layoutCache.find(hash);
|
||||||
|
if (it != m_layoutCache.end()) {
|
||||||
|
return &it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkProgramLayout layout{};
|
||||||
|
layout.hash = hash;
|
||||||
|
if (!ReflectBindingKinds(program, layout.bindingKinds)) {
|
||||||
|
MGLOG_E("ProgramFactory::GetOrCreateProgramLayout failed: reflection failed");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (!ReflectSamplerBindings(program, layout)) {
|
||||||
|
MGLOG_E("ProgramFactory::GetOrCreateProgramLayout failed: sampler reflection failed");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (!ReflectGlobalUboBinding(program, layout)) {
|
||||||
|
MGLOG_E("ProgramFactory::GetOrCreateProgramLayout failed: global UBO reflection failed");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<VkDescriptorSetLayoutBinding> bindings;
|
||||||
|
bindings.reserve(m_maxBindings);
|
||||||
|
for (Uint32 binding = 0; binding < m_maxBindings; ++binding) {
|
||||||
|
const auto kind = layout.bindingKinds[binding];
|
||||||
|
if (kind == DescriptorBindingKind::None) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutBinding layoutBinding{};
|
||||||
|
layoutBinding.binding = binding;
|
||||||
|
layoutBinding.descriptorCount = 1;
|
||||||
|
layoutBinding.stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS;
|
||||||
|
layoutBinding.pImmutableSamplers = nullptr;
|
||||||
|
if (kind == DescriptorBindingKind::UniformBufferDynamic) {
|
||||||
|
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
||||||
|
layout.dynamicBindings.push_back(binding);
|
||||||
|
} else {
|
||||||
|
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
}
|
||||||
|
bindings.push_back(layoutBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutCreateInfo setLayoutInfo{};
|
||||||
|
setLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
|
setLayoutInfo.bindingCount = static_cast<Uint32>(bindings.size());
|
||||||
|
setLayoutInfo.pBindings = bindings.data();
|
||||||
|
VK_VERIFY(vkCreateDescriptorSetLayout(m_device, &setLayoutInfo, nullptr, &layout.descriptorSetLayout),
|
||||||
|
"ProgramFactory::GetOrCreateProgramLayout, vkCreateDescriptorSetLayout");
|
||||||
|
|
||||||
|
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
|
||||||
|
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
|
pipelineLayoutInfo.setLayoutCount = 1;
|
||||||
|
pipelineLayoutInfo.pSetLayouts = &layout.descriptorSetLayout;
|
||||||
|
VK_VERIFY(vkCreatePipelineLayout(m_device, &pipelineLayoutInfo, nullptr, &layout.pipelineLayout),
|
||||||
|
"ProgramFactory::GetOrCreateProgramLayout, vkCreatePipelineLayout");
|
||||||
|
|
||||||
|
auto [insertIt, _] = m_layoutCache.emplace(hash, std::move(layout));
|
||||||
|
return &insertIt->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipelineLayout ProgramFactory::GetOrCreatePipelineLayout(const MG_State::GLState::ProgramObject& program) {
|
||||||
|
const auto* layout = GetOrCreateProgramLayout(program);
|
||||||
|
return layout ? layout->pipelineLayout : VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProgramFactory::DestroyLayoutCache() {
|
||||||
|
for (auto& [_, layout] : m_layoutCache) {
|
||||||
|
if (layout.pipelineLayout != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyPipelineLayout(m_device, layout.pipelineLayout, nullptr);
|
||||||
|
layout.pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
if (layout.descriptorSetLayout != VK_NULL_HANDLE) {
|
||||||
|
vkDestroyDescriptorSetLayout(m_device, layout.descriptorSetLayout, nullptr);
|
||||||
|
layout.descriptorSetLayout = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_layoutCache.clear();
|
||||||
|
}
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
|
|||||||
@@ -11,11 +11,19 @@
|
|||||||
#include "../VkIncludes.h"
|
#include "../VkIncludes.h"
|
||||||
#include "MG_State/GLState/ProgramState/ProgramObject.h"
|
#include "MG_State/GLState/ProgramState/ProgramObject.h"
|
||||||
#include "MG_State/GLState/ProgramState/ShaderObject.h"
|
#include "MG_State/GLState/ProgramState/ShaderObject.h"
|
||||||
|
#include "MG_State/GLState/TextureState/TextureEnum.h"
|
||||||
|
|
||||||
#include <Includes.h>
|
#include <Includes.h>
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
class ProgramFactory {
|
class ProgramFactory {
|
||||||
public:
|
public:
|
||||||
|
enum class DescriptorBindingKind : Uint8 {
|
||||||
|
None = 0,
|
||||||
|
UniformBufferDynamic,
|
||||||
|
CombinedImageSampler
|
||||||
|
};
|
||||||
|
|
||||||
enum class CompileOptionBit : Uint {
|
enum class CompileOptionBit : Uint {
|
||||||
None = 0,
|
None = 0,
|
||||||
PositionYFlip = 1 << 0,
|
PositionYFlip = 1 << 0,
|
||||||
@@ -26,6 +34,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
};
|
};
|
||||||
using CompileOptionFlags = Flags<CompileOptionBit>;
|
using CompileOptionFlags = Flags<CompileOptionBit>;
|
||||||
using HashType = Uint64;
|
using HashType = Uint64;
|
||||||
|
|
||||||
struct VkProgramObject {
|
struct VkProgramObject {
|
||||||
HashType hash = 0;
|
HashType hash = 0;
|
||||||
Vector<VkPipelineShaderStageCreateInfo> stages;
|
Vector<VkPipelineShaderStageCreateInfo> stages;
|
||||||
@@ -70,8 +79,19 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit ProgramFactory(VkDevice device, const VulkanRendererConfig& config)
|
struct VkProgramLayout {
|
||||||
: m_device(device), m_config(config) {
|
HashType hash = 0;
|
||||||
|
VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
|
||||||
|
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
Vector<DescriptorBindingKind> bindingKinds;
|
||||||
|
Vector<Uint32> dynamicBindings;
|
||||||
|
Vector<Int> samplerUniformLocationByBinding;
|
||||||
|
Vector<TextureTarget> samplerTextureTargetByBinding;
|
||||||
|
Int globalUboBinding = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit ProgramFactory(VkDevice device, const VulkanRendererConfig& config, Uint32 maxBindings = 16)
|
||||||
|
: m_device(device), m_config(config), m_maxBindings(maxBindings) {
|
||||||
VkProgramObject::s_device = device;
|
VkProgramObject::s_device = device;
|
||||||
}
|
}
|
||||||
~ProgramFactory();
|
~ProgramFactory();
|
||||||
@@ -80,12 +100,24 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
HashType ComputeHash(const MG_State::GLState::ProgramObject& program, CompileOptionFlags flags) const;
|
HashType ComputeHash(const MG_State::GLState::ProgramObject& program, CompileOptionFlags flags) const;
|
||||||
Vector<VkPipelineShaderStageCreateInfo>& GetOrCreatePipelineShaderStages(
|
Vector<VkPipelineShaderStageCreateInfo>& GetOrCreatePipelineShaderStages(
|
||||||
const MG_State::GLState::ProgramObject& program, CompileOptionFlags flags);
|
const MG_State::GLState::ProgramObject& program, CompileOptionFlags flags);
|
||||||
|
const VkProgramLayout* GetOrCreateProgramLayout(const MG_State::GLState::ProgramObject& program);
|
||||||
|
VkPipelineLayout GetOrCreatePipelineLayout(const MG_State::GLState::ProgramObject& program);
|
||||||
|
|
||||||
static VkShaderStageFlagBits ToVkStage(ShaderStage stage);
|
static VkShaderStageFlagBits ToVkStage(ShaderStage stage);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
HashType ComputeLayoutHash(const MG_State::GLState::ProgramObject& program) const;
|
||||||
|
static TextureTarget UniformTypeToTextureTarget(GLenum glType);
|
||||||
|
Bool ReflectBindingKinds(const MG_State::GLState::ProgramObject& program,
|
||||||
|
Vector<DescriptorBindingKind>& outKinds) const;
|
||||||
|
Bool ReflectSamplerBindings(const MG_State::GLState::ProgramObject& program, VkProgramLayout& layout) const;
|
||||||
|
Bool ReflectGlobalUboBinding(const MG_State::GLState::ProgramObject& program, VkProgramLayout& layout) const;
|
||||||
|
void DestroyLayoutCache();
|
||||||
|
|
||||||
VkDevice m_device = VK_NULL_HANDLE;
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
|
Uint32 m_maxBindings = 0;
|
||||||
UnorderedMap<HashType, VkProgramObject> m_cache;
|
UnorderedMap<HashType, VkProgramObject> m_cache;
|
||||||
|
UnorderedMap<HashType, VkProgramLayout> m_layoutCache;
|
||||||
const VulkanRendererConfig& m_config;
|
const VulkanRendererConfig& m_config;
|
||||||
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include "MG_State/GLState/Core.h"
|
#include "MG_State/GLState/Core.h"
|
||||||
#include "MG_State/GLState/ProgramState/ProgramObject.h"
|
#include "MG_State/GLState/ProgramState/ProgramObject.h"
|
||||||
#include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h"
|
#include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h"
|
||||||
#include "MG_Util/ShaderTranspiler/Types.h"
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
@@ -54,127 +53,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDeviceSize UniformDescriptorBinder::AlignUp(VkDeviceSize value, VkDeviceSize alignment) {
|
|
||||||
if (alignment == 0) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
return (value + alignment - 1) / alignment * alignment;
|
|
||||||
}
|
|
||||||
|
|
||||||
Uint64 UniformDescriptorBinder::ComputeProgramHash(const MG_State::GLState::ProgramObject& program) {
|
|
||||||
XXH64_state_t* state = XXH64_createState();
|
|
||||||
XXHASH_VERIFY(XXH64_reset(state, 0xC0D3A11ULL));
|
|
||||||
const auto& spirv = program.GetGeneratedSpirv();
|
|
||||||
for (const auto& module : spirv) {
|
|
||||||
XXHASH_VERIFY(XXH64_update(state, module.data(), module.size() * sizeof(Uint)));
|
|
||||||
}
|
|
||||||
const Uint32 blockCount = static_cast<Uint32>(program.GetActiveUniformBlocksCount());
|
|
||||||
XXHASH_VERIFY(XXH64_update(state, &blockCount, sizeof(blockCount)));
|
|
||||||
for (Uint32 i = 0; i < blockCount; ++i) {
|
|
||||||
const Uint32 binding = program.GetUniformBlockBinding(i);
|
|
||||||
XXHASH_VERIFY(XXH64_update(state, &binding, sizeof(binding)));
|
|
||||||
}
|
|
||||||
const Uint64 hash = XXH64_digest(state);
|
|
||||||
XXH64_freeState(state);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::IsSamplerUniformType(GLenum glType) {
|
|
||||||
switch (glType) {
|
|
||||||
case GL_SAMPLER_1D:
|
|
||||||
case GL_SAMPLER_2D:
|
|
||||||
case GL_SAMPLER_3D:
|
|
||||||
case GL_SAMPLER_CUBE:
|
|
||||||
case GL_SAMPLER_1D_SHADOW:
|
|
||||||
case GL_SAMPLER_2D_SHADOW:
|
|
||||||
case GL_SAMPLER_1D_ARRAY:
|
|
||||||
case GL_SAMPLER_2D_ARRAY:
|
|
||||||
case GL_SAMPLER_1D_ARRAY_SHADOW:
|
|
||||||
case GL_SAMPLER_2D_ARRAY_SHADOW:
|
|
||||||
case GL_SAMPLER_2D_MULTISAMPLE:
|
|
||||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
|
||||||
case GL_SAMPLER_CUBE_SHADOW:
|
|
||||||
case GL_SAMPLER_BUFFER:
|
|
||||||
case GL_SAMPLER_2D_RECT:
|
|
||||||
case GL_SAMPLER_2D_RECT_SHADOW:
|
|
||||||
case GL_INT_SAMPLER_1D:
|
|
||||||
case GL_INT_SAMPLER_2D:
|
|
||||||
case GL_INT_SAMPLER_3D:
|
|
||||||
case GL_INT_SAMPLER_CUBE:
|
|
||||||
case GL_INT_SAMPLER_1D_ARRAY:
|
|
||||||
case GL_INT_SAMPLER_2D_ARRAY:
|
|
||||||
case GL_INT_SAMPLER_2D_MULTISAMPLE:
|
|
||||||
case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
|
||||||
case GL_INT_SAMPLER_BUFFER:
|
|
||||||
case GL_INT_SAMPLER_2D_RECT:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_1D:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_3D:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_CUBE:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_BUFFER:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureTarget UniformDescriptorBinder::UniformTypeToTextureTarget(GLenum glType) {
|
|
||||||
switch (glType) {
|
|
||||||
case GL_SAMPLER_1D:
|
|
||||||
case GL_INT_SAMPLER_1D:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_1D:
|
|
||||||
return TextureTarget::Texture1D;
|
|
||||||
case GL_SAMPLER_3D:
|
|
||||||
case GL_INT_SAMPLER_3D:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_3D:
|
|
||||||
return TextureTarget::Texture3D;
|
|
||||||
case GL_SAMPLER_CUBE:
|
|
||||||
case GL_SAMPLER_CUBE_SHADOW:
|
|
||||||
case GL_INT_SAMPLER_CUBE:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_CUBE:
|
|
||||||
return TextureTarget::TextureCubeMap;
|
|
||||||
case GL_SAMPLER_2D_MULTISAMPLE:
|
|
||||||
case GL_INT_SAMPLER_2D_MULTISAMPLE:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
|
|
||||||
return TextureTarget::Texture2DMultisample;
|
|
||||||
case GL_SAMPLER_BUFFER:
|
|
||||||
case GL_INT_SAMPLER_BUFFER:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_BUFFER:
|
|
||||||
return TextureTarget::TextureBuffer;
|
|
||||||
case GL_SAMPLER_1D_ARRAY:
|
|
||||||
case GL_SAMPLER_1D_ARRAY_SHADOW:
|
|
||||||
case GL_INT_SAMPLER_1D_ARRAY:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
|
|
||||||
return TextureTarget::Texture1DArray;
|
|
||||||
case GL_SAMPLER_2D_ARRAY:
|
|
||||||
case GL_SAMPLER_2D_ARRAY_SHADOW:
|
|
||||||
case GL_INT_SAMPLER_2D_ARRAY:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
|
||||||
return TextureTarget::Texture2DArray;
|
|
||||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
|
||||||
case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
|
||||||
return TextureTarget::Texture2DMultisampleArray;
|
|
||||||
case GL_SAMPLER_2D_RECT:
|
|
||||||
case GL_SAMPLER_2D_RECT_SHADOW:
|
|
||||||
case GL_INT_SAMPLER_2D_RECT:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
|
|
||||||
return TextureTarget::TextureRectangle;
|
|
||||||
case GL_SAMPLER_2D:
|
|
||||||
case GL_SAMPLER_2D_SHADOW:
|
|
||||||
case GL_INT_SAMPLER_2D:
|
|
||||||
case GL_UNSIGNED_INT_SAMPLER_2D:
|
|
||||||
default:
|
|
||||||
return TextureTarget::Texture2D;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::Initialize(VkDevice device, VkBufferManager* bufferManager,
|
Bool UniformDescriptorBinder::Initialize(VkDevice device, VkBufferManager* bufferManager,
|
||||||
|
ProgramFactory* programFactory,
|
||||||
VkDeviceSize minUniformBufferOffsetAlignment, Uint32 frameCount,
|
VkDeviceSize minUniformBufferOffsetAlignment, Uint32 frameCount,
|
||||||
Uint32 maxBindings, Uint32 setsPerFrame,
|
Uint32 maxBindings, Uint32 setsPerFrame,
|
||||||
VkTextureManager* textureManager, VkSamplerManager* samplerManager) {
|
VkTextureManager* textureManager, VkSamplerManager* samplerManager) {
|
||||||
@@ -182,6 +62,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
MOBILEGL_ASSERT(device != VK_NULL_HANDLE, "UniformDescriptorBinder::Initialize requires valid VkDevice");
|
MOBILEGL_ASSERT(device != VK_NULL_HANDLE, "UniformDescriptorBinder::Initialize requires valid VkDevice");
|
||||||
MOBILEGL_ASSERT(bufferManager != nullptr, "UniformDescriptorBinder::Initialize requires valid buffer manager");
|
MOBILEGL_ASSERT(bufferManager != nullptr, "UniformDescriptorBinder::Initialize requires valid buffer manager");
|
||||||
|
MOBILEGL_ASSERT(programFactory != nullptr,
|
||||||
|
"UniformDescriptorBinder::Initialize requires valid program factory");
|
||||||
MOBILEGL_ASSERT(frameCount > 0, "UniformDescriptorBinder::Initialize requires frameCount > 0");
|
MOBILEGL_ASSERT(frameCount > 0, "UniformDescriptorBinder::Initialize requires frameCount > 0");
|
||||||
MOBILEGL_ASSERT(maxBindings > 0, "UniformDescriptorBinder::Initialize requires maxBindings > 0");
|
MOBILEGL_ASSERT(maxBindings > 0, "UniformDescriptorBinder::Initialize requires maxBindings > 0");
|
||||||
MOBILEGL_ASSERT(setsPerFrame > 0, "UniformDescriptorBinder::Initialize requires setsPerFrame > 0");
|
MOBILEGL_ASSERT(setsPerFrame > 0, "UniformDescriptorBinder::Initialize requires setsPerFrame > 0");
|
||||||
@@ -192,6 +74,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
m_device = device;
|
m_device = device;
|
||||||
m_bufferManager = bufferManager;
|
m_bufferManager = bufferManager;
|
||||||
|
m_programFactory = programFactory;
|
||||||
m_minDynamicOffsetAlignment = std::max<VkDeviceSize>(1, minUniformBufferOffsetAlignment);
|
m_minDynamicOffsetAlignment = std::max<VkDeviceSize>(1, minUniformBufferOffsetAlignment);
|
||||||
m_frameCount = frameCount;
|
m_frameCount = frameCount;
|
||||||
m_maxBindings = maxBindings;
|
m_maxBindings = maxBindings;
|
||||||
@@ -216,7 +99,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
frame.descriptorPools.push_back({initialPool, m_setsPerFrame, 0});
|
frame.descriptorPools.push_back({initialPool, m_setsPerFrame, 0});
|
||||||
MGLOG_D("UniformDescriptorBinder: frame %u descriptor pool created (maxSets=%u)", frameIndex, m_setsPerFrame);
|
MGLOG_D("UniformDescriptorBinder: frame %u descriptor pool created (maxSets=%u)", frameIndex,
|
||||||
|
m_setsPerFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -238,9 +122,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
frame.peakAllocatedSetsThisFrame = 0;
|
frame.peakAllocatedSetsThisFrame = 0;
|
||||||
}
|
}
|
||||||
m_frames.clear();
|
m_frames.clear();
|
||||||
DestroyProgramLayouts();
|
|
||||||
|
|
||||||
m_bufferManager = nullptr;
|
m_bufferManager = nullptr;
|
||||||
|
m_programFactory = nullptr;
|
||||||
m_device = VK_NULL_HANDLE;
|
m_device = VK_NULL_HANDLE;
|
||||||
m_minDynamicOffsetAlignment = 1;
|
m_minDynamicOffsetAlignment = 1;
|
||||||
m_frameCount = 0;
|
m_frameCount = 0;
|
||||||
@@ -273,203 +157,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::ReflectBindingKinds(const MG_State::GLState::ProgramObject& program,
|
|
||||||
Vector<BindingKind>& outKinds) const {
|
|
||||||
outKinds.assign(m_maxBindings, BindingKind::None);
|
|
||||||
|
|
||||||
const auto& spirv = program.GetGeneratedSpirv();
|
|
||||||
for (const auto& module : spirv) {
|
|
||||||
if (module.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
spvc_context context = nullptr;
|
|
||||||
spvc_parsed_ir ir = nullptr;
|
|
||||||
spvc_compiler compiler = nullptr;
|
|
||||||
spvc_resources resources = nullptr;
|
|
||||||
|
|
||||||
if (spvc_context_create(&context) != SPVC_SUCCESS) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const spvc_result parseResult = spvc_context_parse_spirv(context, module.data(), module.size(), &ir);
|
|
||||||
if (parseResult != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const spvc_result compilerResult =
|
|
||||||
spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler);
|
|
||||||
if (compilerResult != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spvc_compiler_create_shader_resources(compiler, &resources) != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto applyBindings = [&](spvc_resource_type resourceType, BindingKind kind) {
|
|
||||||
const spvc_reflected_resource* list = nullptr;
|
|
||||||
size_t count = 0;
|
|
||||||
if (spvc_resources_get_resource_list_for_type(resources, resourceType, &list, &count) != SPVC_SUCCESS) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
|
||||||
const Uint32 binding =
|
|
||||||
spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding);
|
|
||||||
if (binding >= m_maxBindings) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (kind == BindingKind::CombinedImageSampler) {
|
|
||||||
outKinds[binding] = BindingKind::CombinedImageSampler;
|
|
||||||
} else if (outKinds[binding] == BindingKind::None) {
|
|
||||||
outKinds[binding] = kind;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
applyBindings(SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, BindingKind::UniformBufferDynamic);
|
|
||||||
applyBindings(SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, BindingKind::CombinedImageSampler);
|
|
||||||
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::ReflectSamplerBindings(const MG_State::GLState::ProgramObject& program,
|
|
||||||
ProgramLayout& layout) const {
|
|
||||||
layout.samplerUniformLocationByBinding.assign(m_maxBindings, -1);
|
|
||||||
layout.samplerTextureTargetByBinding.assign(m_maxBindings, TextureTarget::Texture2D);
|
|
||||||
|
|
||||||
const auto& spirv = program.GetGeneratedSpirv();
|
|
||||||
for (const auto& module : spirv) {
|
|
||||||
if (module.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
spvc_context context = nullptr;
|
|
||||||
spvc_parsed_ir ir = nullptr;
|
|
||||||
spvc_compiler compiler = nullptr;
|
|
||||||
spvc_resources resources = nullptr;
|
|
||||||
|
|
||||||
if (spvc_context_create(&context) != SPVC_SUCCESS) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (spvc_context_parse_spirv(context, module.data(), module.size(), &ir) != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP,
|
|
||||||
&compiler) != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (spvc_compiler_create_shader_resources(compiler, &resources) != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const spvc_reflected_resource* list = nullptr;
|
|
||||||
size_t count = 0;
|
|
||||||
if (spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, &list, &count) ==
|
|
||||||
SPVC_SUCCESS) {
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
|
||||||
const Uint32 binding =
|
|
||||||
spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding);
|
|
||||||
if (binding >= m_maxBindings) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String uniformName = list[i].name ? list[i].name : "";
|
|
||||||
Int location = program.GetUniformLocation(uniformName);
|
|
||||||
if (location < 0) {
|
|
||||||
const auto arraySuffix = uniformName.find("[0]");
|
|
||||||
if (arraySuffix != String::npos) {
|
|
||||||
uniformName = uniformName.substr(0, arraySuffix);
|
|
||||||
location = program.GetUniformLocation(uniformName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (location < 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
layout.samplerUniformLocationByBinding[binding] = location;
|
|
||||||
layout.samplerTextureTargetByBinding[binding] =
|
|
||||||
UniformTypeToTextureTarget(program.GetUniformType(static_cast<Uint>(location)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::ReflectGlobalUboBinding(const MG_State::GLState::ProgramObject& program,
|
|
||||||
ProgramLayout& layout) const {
|
|
||||||
layout.globalUboBinding = -1;
|
|
||||||
|
|
||||||
const auto& spirv = program.GetGeneratedSpirv();
|
|
||||||
for (const auto& module : spirv) {
|
|
||||||
if (module.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
spvc_context context = nullptr;
|
|
||||||
spvc_parsed_ir ir = nullptr;
|
|
||||||
spvc_compiler compiler = nullptr;
|
|
||||||
spvc_resources resources = nullptr;
|
|
||||||
|
|
||||||
if (spvc_context_create(&context) != SPVC_SUCCESS) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (spvc_context_parse_spirv(context, module.data(), module.size(), &ir) != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP,
|
|
||||||
&compiler) != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (spvc_compiler_create_shader_resources(compiler, &resources) != SPVC_SUCCESS) {
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const spvc_reflected_resource* list = nullptr;
|
|
||||||
size_t count = 0;
|
|
||||||
if (spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &list, &count) ==
|
|
||||||
SPVC_SUCCESS) {
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
|
||||||
const char* name = list[i].name ? list[i].name : "";
|
|
||||||
if (std::strstr(name, MG_Util::ShaderTranspiler::GLOBAL_UBO_NAME) == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const Uint32 binding =
|
|
||||||
spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationBinding);
|
|
||||||
if (binding < m_maxBindings) {
|
|
||||||
layout.globalUboBinding = static_cast<Int>(binding);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spvc_context_destroy(context);
|
|
||||||
if (layout.globalUboBinding >= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::ResolveSamplerDescriptor(VkCommandBuffer commandBuffer,
|
Bool UniformDescriptorBinder::ResolveSamplerDescriptor(VkCommandBuffer commandBuffer,
|
||||||
const MG_State::GLState::ProgramObject& program,
|
const MG_State::GLState::ProgramObject& program,
|
||||||
const ProgramLayout& layout, Uint32 binding,
|
const ProgramFactory::VkProgramLayout& layout,
|
||||||
VkDescriptorImageInfo& outImageInfo) const {
|
Uint32 binding, VkDescriptorImageInfo& outImageInfo) const {
|
||||||
(void)commandBuffer;
|
(void)commandBuffer;
|
||||||
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptor: texture manager is null");
|
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptor: texture manager is null");
|
||||||
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptor: sampler manager is null");
|
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptor: sampler manager is null");
|
||||||
@@ -486,12 +177,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MG_State::GLState::SamplerObject* samplerToUse = samplerOverride ? samplerOverride.get() : texture->GetSamplerObject().get();
|
const MG_State::GLState::SamplerObject* samplerToUse =
|
||||||
|
samplerOverride ? samplerOverride.get() : texture->GetSamplerObject().get();
|
||||||
if (!samplerToUse) {
|
if (!samplerToUse) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
VkTextureManager::TextureResource* resource =
|
VkTextureManager::TextureResource* resource = m_textureManager->SyncTextureAndGetDescriptor(*texture);
|
||||||
m_textureManager->SyncTextureAndGetDescriptor(*texture);
|
|
||||||
if (resource == nullptr) {
|
if (resource == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -524,8 +215,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::ResolveSamplerDescriptorOverride(
|
Bool UniformDescriptorBinder::ResolveSamplerDescriptorOverride(
|
||||||
const SamplerBindingOverride& samplerBindingOverride,
|
const SamplerBindingOverride& samplerBindingOverride, VkDescriptorImageInfo& outImageInfo) const {
|
||||||
VkDescriptorImageInfo& outImageInfo) const {
|
|
||||||
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptorOverride: texture manager is null");
|
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptorOverride: texture manager is null");
|
||||||
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptorOverride: sampler manager is null");
|
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptorOverride: sampler manager is null");
|
||||||
if (samplerBindingOverride.texture == nullptr || samplerBindingOverride.sampler == nullptr) {
|
if (samplerBindingOverride.texture == nullptr || samplerBindingOverride.sampler == nullptr) {
|
||||||
@@ -546,7 +236,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program,
|
Bool UniformDescriptorBinder::ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program,
|
||||||
const ProgramLayout& layout, Uint32 binding,
|
const ProgramFactory::VkProgramLayout& layout, Uint32 binding,
|
||||||
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) const {
|
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) const {
|
||||||
outTexture.reset();
|
outTexture.reset();
|
||||||
if (!MG_State::pGLContext || binding >= layout.samplerUniformLocationByBinding.size()) {
|
if (!MG_State::pGLContext || binding >= layout.samplerUniformLocationByBinding.size()) {
|
||||||
@@ -572,13 +262,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Bool UniformDescriptorBinder::CollectSampledTextures(const MG_State::GLState::ProgramObject& program,
|
Bool UniformDescriptorBinder::CollectSampledTextures(const MG_State::GLState::ProgramObject& program,
|
||||||
Vector<MG_State::GLState::ITextureObject*>& outTextures) {
|
Vector<MG_State::GLState::ITextureObject*>& outTextures) {
|
||||||
outTextures.clear();
|
outTextures.clear();
|
||||||
ProgramLayout* layout = GetOrCreateProgramLayout(program);
|
MOBILEGL_ASSERT(m_programFactory != nullptr, "CollectSampledTextures: program factory is null");
|
||||||
|
const auto* layout = m_programFactory->GetOrCreateProgramLayout(program);
|
||||||
if (layout == nullptr) {
|
if (layout == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Uint32 binding = 0; binding < m_maxBindings; ++binding) {
|
const Uint32 bindingCount =
|
||||||
if (layout->bindingKinds[binding] != BindingKind::CombinedImageSampler) {
|
std::min<Uint32>(m_maxBindings, static_cast<Uint32>(layout->bindingKinds.size()));
|
||||||
|
for (Uint32 binding = 0; binding < bindingCount; ++binding) {
|
||||||
|
if (layout->bindingKinds[binding] != ProgramFactory::DescriptorBindingKind::CombinedImageSampler) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,74 +288,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
UniformDescriptorBinder::ProgramLayout* UniformDescriptorBinder::GetOrCreateProgramLayout(
|
|
||||||
const MG_State::GLState::ProgramObject& program) {
|
|
||||||
const Uint64 hash = ComputeProgramHash(program);
|
|
||||||
auto it = m_programLayouts.find(hash);
|
|
||||||
if (it != m_programLayouts.end()) {
|
|
||||||
return &it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProgramLayout layout{};
|
|
||||||
layout.hash = hash;
|
|
||||||
if (!ReflectBindingKinds(program, layout.bindingKinds)) {
|
|
||||||
MGLOG_E("UniformDescriptorBinder::GetOrCreateProgramLayout failed: reflection failed");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (!ReflectSamplerBindings(program, layout)) {
|
|
||||||
MGLOG_E("UniformDescriptorBinder::GetOrCreateProgramLayout failed: sampler reflection failed");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (!ReflectGlobalUboBinding(program, layout)) {
|
|
||||||
MGLOG_E("UniformDescriptorBinder::GetOrCreateProgramLayout failed: global UBO reflection failed");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<VkDescriptorSetLayoutBinding> bindings;
|
|
||||||
bindings.reserve(m_maxBindings);
|
|
||||||
for (Uint32 binding = 0; binding < m_maxBindings; ++binding) {
|
|
||||||
const auto kind = layout.bindingKinds[binding];
|
|
||||||
if (kind == BindingKind::None) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorSetLayoutBinding layoutBinding{};
|
|
||||||
layoutBinding.binding = binding;
|
|
||||||
layoutBinding.descriptorCount = 1;
|
|
||||||
layoutBinding.stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS;
|
|
||||||
layoutBinding.pImmutableSamplers = nullptr;
|
|
||||||
if (kind == BindingKind::UniformBufferDynamic) {
|
|
||||||
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
|
||||||
layout.dynamicBindings.push_back(binding);
|
|
||||||
} else {
|
|
||||||
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
||||||
}
|
|
||||||
bindings.push_back(layoutBinding);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorSetLayoutCreateInfo setLayoutInfo{};
|
|
||||||
setLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
|
||||||
setLayoutInfo.bindingCount = static_cast<Uint32>(bindings.size());
|
|
||||||
setLayoutInfo.pBindings = bindings.data();
|
|
||||||
VK_VERIFY(vkCreateDescriptorSetLayout(m_device, &setLayoutInfo, nullptr, &layout.descriptorSetLayout),
|
|
||||||
"UniformDescriptorBinder::GetOrCreateProgramLayout, vkCreateDescriptorSetLayout");
|
|
||||||
|
|
||||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
|
|
||||||
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
|
||||||
pipelineLayoutInfo.setLayoutCount = 1;
|
|
||||||
pipelineLayoutInfo.pSetLayouts = &layout.descriptorSetLayout;
|
|
||||||
VK_VERIFY(vkCreatePipelineLayout(m_device, &pipelineLayoutInfo, nullptr, &layout.pipelineLayout),
|
|
||||||
"UniformDescriptorBinder::GetOrCreateProgramLayout, vkCreatePipelineLayout");
|
|
||||||
|
|
||||||
auto [insertIt, _] = m_programLayouts.emplace(hash, std::move(layout));
|
|
||||||
return &insertIt->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkPipelineLayout UniformDescriptorBinder::GetOrCreatePipelineLayout(const MG_State::GLState::ProgramObject& program) {
|
|
||||||
auto* layout = GetOrCreateProgramLayout(program);
|
|
||||||
return layout ? layout->pipelineLayout : VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bool UniformDescriptorBinder::GatherBindingPayloads(const MG_State::GLState::ProgramObject& program,
|
Bool UniformDescriptorBinder::GatherBindingPayloads(const MG_State::GLState::ProgramObject& program,
|
||||||
Vector<const void*>& outData,
|
Vector<const void*>& outData,
|
||||||
Vector<VkDeviceSize>& outSizes) const {
|
Vector<VkDeviceSize>& outSizes) const {
|
||||||
@@ -749,7 +374,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
const VkResult result = vkCreateDescriptorPool(m_device, &poolInfo, nullptr, &outPool);
|
const VkResult result = vkCreateDescriptorPool(m_device, &poolInfo, nullptr, &outPool);
|
||||||
if (result != VK_SUCCESS) {
|
if (result != VK_SUCCESS) {
|
||||||
MGLOG_E("UniformDescriptorBinder::CreateDescriptorPool failed: vkCreateDescriptorPool returned %d", result);
|
MGLOG_E("UniformDescriptorBinder::CreateDescriptorPool failed: vkCreateDescriptorPool returned %d",
|
||||||
|
result);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -790,7 +416,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
const MG_State::GLState::ProgramObject& program,
|
const MG_State::GLState::ProgramObject& program,
|
||||||
Uint32 frameIndex,
|
Uint32 frameIndex,
|
||||||
const SamplerBindingOverride* samplerBindingOverride) {
|
const SamplerBindingOverride* samplerBindingOverride) {
|
||||||
ProgramLayout* layout = GetOrCreateProgramLayout(program);
|
MOBILEGL_ASSERT(m_programFactory != nullptr, "BindProgramUniformBuffers: program factory is null");
|
||||||
|
const auto* layout = m_programFactory->GetOrCreateProgramLayout(program);
|
||||||
MOBILEGL_ASSERT(layout != nullptr,
|
MOBILEGL_ASSERT(layout != nullptr,
|
||||||
"UniformDescriptorBinder::BindProgramUniformBuffers: program layout is null");
|
"UniformDescriptorBinder::BindProgramUniformBuffers: program layout is null");
|
||||||
|
|
||||||
@@ -816,7 +443,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
if (outResult == VK_SUCCESS) {
|
if (outResult == VK_SUCCESS) {
|
||||||
++bucket.allocatedSets;
|
++bucket.allocatedSets;
|
||||||
++frame.allocatedSetsThisFrame;
|
++frame.allocatedSetsThisFrame;
|
||||||
frame.peakAllocatedSetsThisFrame = std::max(frame.peakAllocatedSetsThisFrame, frame.allocatedSetsThisFrame);
|
frame.peakAllocatedSetsThisFrame =
|
||||||
|
std::max(frame.peakAllocatedSetsThisFrame, frame.allocatedSetsThisFrame);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -856,9 +484,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
imageInfos.reserve(m_maxBindings);
|
imageInfos.reserve(m_maxBindings);
|
||||||
dynamicOffsets.reserve(layout->dynamicBindings.size());
|
dynamicOffsets.reserve(layout->dynamicBindings.size());
|
||||||
|
|
||||||
for (Uint32 binding = 0; binding < m_maxBindings; ++binding) {
|
const Uint32 bindingCount =
|
||||||
|
std::min<Uint32>(m_maxBindings, static_cast<Uint32>(layout->bindingKinds.size()));
|
||||||
|
for (Uint32 binding = 0; binding < bindingCount; ++binding) {
|
||||||
const auto kind = layout->bindingKinds[binding];
|
const auto kind = layout->bindingKinds[binding];
|
||||||
if (kind == BindingKind::None) {
|
if (kind == ProgramFactory::DescriptorBindingKind::None) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -869,7 +499,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
write.dstArrayElement = 0;
|
write.dstArrayElement = 0;
|
||||||
write.descriptorCount = 1;
|
write.descriptorCount = 1;
|
||||||
|
|
||||||
if (kind == BindingKind::UniformBufferDynamic) {
|
if (kind == ProgramFactory::DescriptorBindingKind::UniformBufferDynamic) {
|
||||||
const void* payload = bindingData[binding];
|
const void* payload = bindingData[binding];
|
||||||
VkDeviceSize payloadSize = bindingSizes[binding];
|
VkDeviceSize payloadSize = bindingSizes[binding];
|
||||||
if (payload == nullptr || payloadSize == 0) {
|
if (payload == nullptr || payloadSize == 0) {
|
||||||
@@ -937,22 +567,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
vkUpdateDescriptorSets(m_device, static_cast<Uint32>(writes.size()), writes.data(), 0, nullptr);
|
vkUpdateDescriptorSets(m_device, static_cast<Uint32>(writes.size()), writes.data(), 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, layout->pipelineLayout, 0, 1, &descriptorSet,
|
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, layout->pipelineLayout, 0, 1,
|
||||||
static_cast<Uint32>(dynamicOffsets.size()), dynamicOffsets.data());
|
&descriptorSet, static_cast<Uint32>(dynamicOffsets.size()), dynamicOffsets.data());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UniformDescriptorBinder::DestroyProgramLayouts() {
|
|
||||||
for (auto& [_, layout] : m_programLayouts) {
|
|
||||||
if (layout.pipelineLayout != VK_NULL_HANDLE) {
|
|
||||||
vkDestroyPipelineLayout(m_device, layout.pipelineLayout, nullptr);
|
|
||||||
layout.pipelineLayout = VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
if (layout.descriptorSetLayout != VK_NULL_HANDLE) {
|
|
||||||
vkDestroyDescriptorSetLayout(m_device, layout.descriptorSetLayout, nullptr);
|
|
||||||
layout.descriptorSetLayout = VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_programLayouts.clear();
|
|
||||||
}
|
|
||||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "ProgramFactory.h"
|
||||||
#include "VkBufferManager.h"
|
#include "VkBufferManager.h"
|
||||||
#include "VkSamplerManager.h"
|
#include "VkSamplerManager.h"
|
||||||
#include "VkTextureManager.h"
|
#include "VkTextureManager.h"
|
||||||
@@ -23,12 +24,6 @@ namespace MobileGL::MG_State::GLState {
|
|||||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||||
class UniformDescriptorBinder {
|
class UniformDescriptorBinder {
|
||||||
public:
|
public:
|
||||||
enum class BindingKind : Uint8 {
|
|
||||||
None = 0,
|
|
||||||
UniformBufferDynamic,
|
|
||||||
CombinedImageSampler
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SamplerBindingOverride {
|
struct SamplerBindingOverride {
|
||||||
Uint32 binding = 0;
|
Uint32 binding = 0;
|
||||||
MG_State::GLState::ITextureObject* texture = nullptr;
|
MG_State::GLState::ITextureObject* texture = nullptr;
|
||||||
@@ -36,13 +31,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Bool Initialize(VkDevice device, VkBufferManager* bufferManager,
|
Bool Initialize(VkDevice device, VkBufferManager* bufferManager,
|
||||||
|
ProgramFactory* programFactory,
|
||||||
VkDeviceSize minUniformBufferOffsetAlignment, Uint32 frameCount,
|
VkDeviceSize minUniformBufferOffsetAlignment, Uint32 frameCount,
|
||||||
Uint32 maxBindings = 16, Uint32 setsPerFrame = 64,
|
Uint32 maxBindings = 16, Uint32 setsPerFrame = 64,
|
||||||
VkTextureManager* textureManager = nullptr, VkSamplerManager* samplerManager = nullptr);
|
VkTextureManager* textureManager = nullptr, VkSamplerManager* samplerManager = nullptr);
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
void BeginFrame(Uint32 frameIndex);
|
void BeginFrame(Uint32 frameIndex);
|
||||||
VkPipelineLayout GetOrCreatePipelineLayout(const MG_State::GLState::ProgramObject& program);
|
|
||||||
Bool CollectSampledTextures(const MG_State::GLState::ProgramObject& program,
|
Bool CollectSampledTextures(const MG_State::GLState::ProgramObject& program,
|
||||||
Vector<MG_State::GLState::ITextureObject*>& outTextures);
|
Vector<MG_State::GLState::ITextureObject*>& outTextures);
|
||||||
Bool BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
Bool BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
||||||
@@ -65,42 +60,23 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
Uint32 peakAllocatedSetsThisFrame = 0;
|
Uint32 peakAllocatedSetsThisFrame = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ProgramLayout {
|
Bool ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program,
|
||||||
Uint64 hash = 0;
|
const ProgramFactory::VkProgramLayout& layout, Uint32 binding,
|
||||||
VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
|
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) const;
|
||||||
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
|
|
||||||
Vector<BindingKind> bindingKinds;
|
|
||||||
Vector<Uint32> dynamicBindings;
|
|
||||||
Vector<Int> samplerUniformLocationByBinding;
|
|
||||||
Vector<TextureTarget> samplerTextureTargetByBinding;
|
|
||||||
Int globalUboBinding = -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
static VkDeviceSize AlignUp(VkDeviceSize value, VkDeviceSize alignment);
|
|
||||||
static Uint64 ComputeProgramHash(const MG_State::GLState::ProgramObject& program);
|
|
||||||
static Bool IsSamplerUniformType(GLenum glType);
|
|
||||||
static TextureTarget UniformTypeToTextureTarget(GLenum glType);
|
|
||||||
Bool ReflectSamplerBindings(const MG_State::GLState::ProgramObject& program, ProgramLayout& layout) const;
|
|
||||||
Bool ReflectGlobalUboBinding(const MG_State::GLState::ProgramObject& program, ProgramLayout& layout) const;
|
|
||||||
Bool ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program, const ProgramLayout& layout,
|
|
||||||
Uint32 binding, SharedPtr<MG_State::GLState::ITextureObject>& outTexture) const;
|
|
||||||
Bool ResolveSamplerDescriptor(VkCommandBuffer commandBuffer, const MG_State::GLState::ProgramObject& program,
|
Bool ResolveSamplerDescriptor(VkCommandBuffer commandBuffer, const MG_State::GLState::ProgramObject& program,
|
||||||
const ProgramLayout& layout, Uint32 binding,
|
const ProgramFactory::VkProgramLayout& layout, Uint32 binding,
|
||||||
VkDescriptorImageInfo& outImageInfo) const;
|
VkDescriptorImageInfo& outImageInfo) const;
|
||||||
Bool ResolveSamplerDescriptorOverride(const SamplerBindingOverride& samplerBindingOverride,
|
Bool ResolveSamplerDescriptorOverride(const SamplerBindingOverride& samplerBindingOverride,
|
||||||
VkDescriptorImageInfo& outImageInfo) const;
|
VkDescriptorImageInfo& outImageInfo) const;
|
||||||
Bool ReflectBindingKinds(const MG_State::GLState::ProgramObject& program, Vector<BindingKind>& outKinds) const;
|
|
||||||
ProgramLayout* GetOrCreateProgramLayout(const MG_State::GLState::ProgramObject& program);
|
|
||||||
Bool GatherBindingPayloads(const MG_State::GLState::ProgramObject& program, Vector<const void*>& outData,
|
Bool GatherBindingPayloads(const MG_State::GLState::ProgramObject& program, Vector<const void*>& outData,
|
||||||
Vector<VkDeviceSize>& outSizes) const;
|
Vector<VkDeviceSize>& outSizes) const;
|
||||||
Bool CreateDescriptorPool(Uint32 maxSets, VkDescriptorPool& outPool) const;
|
Bool CreateDescriptorPool(Uint32 maxSets, VkDescriptorPool& outPool) const;
|
||||||
Bool GrowFrameDescriptorPool(FrameResources& frame, Uint32 frameIndex);
|
Bool GrowFrameDescriptorPool(FrameResources& frame, Uint32 frameIndex);
|
||||||
void DestroyProgramLayouts();
|
|
||||||
|
|
||||||
VkDevice m_device = VK_NULL_HANDLE;
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
VkBufferManager* m_bufferManager = nullptr;
|
VkBufferManager* m_bufferManager = nullptr;
|
||||||
|
ProgramFactory* m_programFactory = nullptr;
|
||||||
Vector<FrameResources> m_frames;
|
Vector<FrameResources> m_frames;
|
||||||
UnorderedMap<Uint64, ProgramLayout> m_programLayouts;
|
|
||||||
|
|
||||||
VkDeviceSize m_minDynamicOffsetAlignment = 1;
|
VkDeviceSize m_minDynamicOffsetAlignment = 1;
|
||||||
Uint32 m_frameCount = 0;
|
Uint32 m_frameCount = 0;
|
||||||
|
|||||||
@@ -98,6 +98,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
static constexpr Uint32 kMaxProgramBindings = 16;
|
||||||
|
static constexpr Uint32 kDescriptorSetsPerFrame = 64;
|
||||||
static constexpr Uint kHiddenBlitProgramId = 0xFFFFFFF0u;
|
static constexpr Uint kHiddenBlitProgramId = 0xFFFFFFF0u;
|
||||||
static constexpr Uint kHiddenBlitVertexShaderId = 0xFFFFFFF1u;
|
static constexpr Uint kHiddenBlitVertexShaderId = 0xFFFFFFF1u;
|
||||||
static constexpr Uint kHiddenBlitFragmentShaderId = 0xFFFFFFF2u;
|
static constexpr Uint kHiddenBlitFragmentShaderId = 0xFFFFFFF2u;
|
||||||
@@ -339,7 +341,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
m_pipelineFactory = MakeUnique<PipelineFactory>(m_device, m_config);
|
m_pipelineFactory = MakeUnique<PipelineFactory>(m_device, m_config);
|
||||||
MOBILEGL_ASSERT(m_pipelineFactory != nullptr, "PipelineFactory creation failed.");
|
MOBILEGL_ASSERT(m_pipelineFactory != nullptr, "PipelineFactory creation failed.");
|
||||||
m_programFactory = MakeUnique<ProgramFactory>(m_device, m_config);
|
m_programFactory = MakeUnique<ProgramFactory>(m_device, m_config, kMaxProgramBindings);
|
||||||
MOBILEGL_ASSERT(m_programFactory != nullptr, "ProgramFactory creation failed.");
|
MOBILEGL_ASSERT(m_programFactory != nullptr, "ProgramFactory creation failed.");
|
||||||
|
|
||||||
m_samplerManager = MakeUnique<VkSamplerManager>();
|
m_samplerManager = MakeUnique<VkSamplerManager>();
|
||||||
@@ -351,10 +353,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
m_uniformDescriptorBinder = MakeUnique<UniformDescriptorBinder>();
|
m_uniformDescriptorBinder = MakeUnique<UniformDescriptorBinder>();
|
||||||
MOBILEGL_ASSERT(m_uniformDescriptorBinder != nullptr, "UniformDescriptorBinder creation failed.");
|
MOBILEGL_ASSERT(m_uniformDescriptorBinder != nullptr, "UniformDescriptorBinder creation failed.");
|
||||||
succeeded = m_uniformDescriptorBinder->Initialize(m_device, &m_bufferManager,
|
succeeded = m_uniformDescriptorBinder->Initialize(
|
||||||
m_physicalDevice.properties.limits.minUniformBufferOffsetAlignment,
|
m_device, &m_bufferManager, m_programFactory.get(),
|
||||||
m_config.MaxFramesInFlight, 16, 64,
|
m_physicalDevice.properties.limits.minUniformBufferOffsetAlignment, m_config.MaxFramesInFlight,
|
||||||
m_textureManager.get(), m_samplerManager.get());
|
kMaxProgramBindings, kDescriptorSetsPerFrame, m_textureManager.get(), m_samplerManager.get());
|
||||||
MOBILEGL_ASSERT(succeeded, "UniformDescriptorBinder initialization failed.");
|
MOBILEGL_ASSERT(succeeded, "UniformDescriptorBinder initialization failed.");
|
||||||
m_vertexInputStateFactory = MakeUnique<VertexInputStateFactory>(m_config);
|
m_vertexInputStateFactory = MakeUnique<VertexInputStateFactory>(m_config);
|
||||||
MOBILEGL_ASSERT(m_vertexInputStateFactory != nullptr, "VertexInputStateFactory creation failed.");
|
MOBILEGL_ASSERT(m_vertexInputStateFactory != nullptr, "VertexInputStateFactory creation failed.");
|
||||||
@@ -372,7 +374,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
VK_VERIFY(vkDeviceWaitIdle(m_device));
|
VK_VERIFY(vkDeviceWaitIdle(m_device));
|
||||||
|
|
||||||
m_pipelineFactory.reset();
|
m_pipelineFactory.reset();
|
||||||
m_programFactory.reset();
|
|
||||||
ShutdownBlitResources();
|
ShutdownBlitResources();
|
||||||
if (m_samplerManager) {
|
if (m_samplerManager) {
|
||||||
m_samplerManager->Shutdown();
|
m_samplerManager->Shutdown();
|
||||||
@@ -392,6 +393,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
m_uniformDescriptorBinder->Shutdown();
|
m_uniformDescriptorBinder->Shutdown();
|
||||||
m_uniformDescriptorBinder.reset();
|
m_uniformDescriptorBinder.reset();
|
||||||
}
|
}
|
||||||
|
m_programFactory.reset();
|
||||||
|
|
||||||
ShutdownSwapchain();
|
ShutdownSwapchain();
|
||||||
m_renderPassManager.reset();
|
m_renderPassManager.reset();
|
||||||
@@ -669,7 +671,7 @@ void main() {
|
|||||||
PipelineFactory::PipelineCreatePayload payload{
|
PipelineFactory::PipelineCreatePayload payload{
|
||||||
.programHash = m_programFactory->ComputeHash(*m_blitResources.program, transformFlags),
|
.programHash = m_programFactory->ComputeHash(*m_blitResources.program, transformFlags),
|
||||||
.vertexInputHash = 0,
|
.vertexInputHash = 0,
|
||||||
.pipelineLayout = m_uniformDescriptorBinder->GetOrCreatePipelineLayout(*m_blitResources.program),
|
.pipelineLayout = m_programFactory->GetOrCreatePipelineLayout(*m_blitResources.program),
|
||||||
.renderPass = renderPassEntry.renderPass,
|
.renderPass = renderPassEntry.renderPass,
|
||||||
.subpass = 0,
|
.subpass = 0,
|
||||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
||||||
@@ -707,7 +709,7 @@ void main() {
|
|||||||
|
|
||||||
auto vertexInputHash = m_vertexInputStateFactory->ComputeHash(vao);
|
auto vertexInputHash = m_vertexInputStateFactory->ComputeHash(vao);
|
||||||
auto& vis = m_vertexInputStateFactory->GetOrCreateVertexInputState(vao);
|
auto& vis = m_vertexInputStateFactory->GetOrCreateVertexInputState(vao);
|
||||||
auto pipelineLayout = m_uniformDescriptorBinder->GetOrCreatePipelineLayout(program);
|
auto pipelineLayout = m_programFactory->GetOrCreatePipelineLayout(program);
|
||||||
auto cullFaceEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::CullFace);
|
auto cullFaceEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::CullFace);
|
||||||
auto depthTestEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::DepthTest);
|
auto depthTestEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::DepthTest);
|
||||||
BlendFactor srcRGB = BlendFactor::One;
|
BlendFactor srcRGB = BlendFactor::One;
|
||||||
|
|||||||
Reference in New Issue
Block a user