mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +09:00
[Refactor] (MG_Backend/DirectVulkan/ProgramFactory): refactor uniform reflection
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "ProgramFactory.h"
|
||||
|
||||
#include "MG_Util/ShaderTranspiler/SpvcSession.h"
|
||||
#include "MG_Util/ShaderTranspiler/Types.h"
|
||||
#include <cstring>
|
||||
#include <spirv-tools/libspirv.h>
|
||||
@@ -23,6 +24,8 @@
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
namespace {
|
||||
using ShaderObject = MG_State::GLState::ShaderObject;
|
||||
using SpvcSession = MG_Util::ShaderTranspiler::SpvcSession;
|
||||
using SessionUsageBit = MG_Util::ShaderTranspiler::SessionUsageBit;
|
||||
|
||||
struct PositionTargetInfo {
|
||||
Uint32 variableId = 0;
|
||||
@@ -323,10 +326,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ProgramFactory::~ProgramFactory() {
|
||||
DestroyLayoutCache();
|
||||
}
|
||||
|
||||
VkShaderStageFlagBits ProgramFactory::ToVkStage(ShaderStage stage) {
|
||||
switch (stage) {
|
||||
case ShaderStage::Vertex:
|
||||
@@ -355,24 +354,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, spv.data(), spv.size() * sizeof(Uint)));
|
||||
}
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &flags, sizeof(CompileOptionFlags)));
|
||||
HashType hash = XXH64_digest(m_hashState);
|
||||
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)));
|
||||
}
|
||||
|
||||
// Include UBO block bindings in hash so different binding configurations produce different entries
|
||||
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);
|
||||
|
||||
HashType hash = XXH64_digest(m_hashState);
|
||||
return hash;
|
||||
}
|
||||
|
||||
TextureTarget ProgramFactory::UniformTypeToTextureTarget(GLenum glType) {
|
||||
@@ -426,205 +418,117 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
}
|
||||
|
||||
Bool ProgramFactory::ReflectBindingKinds(const MG_State::GLState::ProgramObject& program,
|
||||
Vector<DescriptorBindingKind>& outKinds) const {
|
||||
outKinds.assign(m_maxBindings, DescriptorBindingKind::None);
|
||||
void ProgramFactory::ReflectLayout(const MG_State::GLState::ProgramObject& program,
|
||||
VkProgramObject& entry) const {
|
||||
// Initialize layout vectors
|
||||
entry.bindingKinds.assign(m_maxBindings, DescriptorBindingKind::None);
|
||||
entry.samplerUniformLocationByBinding.assign(m_maxBindings, -1);
|
||||
entry.samplerTextureTargetByBinding.assign(m_maxBindings, TextureTarget::Texture2D);
|
||||
entry.globalUboBinding = -1;
|
||||
entry.dynamicBindings.clear();
|
||||
|
||||
// Use SpvcSession (Reflection mode) to reflect all SPIR-V modules in a single pass per module
|
||||
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;
|
||||
SpvcSession session(module, SessionUsageBit::Reflection);
|
||||
|
||||
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;
|
||||
// Reflect uniform buffers
|
||||
auto ubos = session.GetShaderInterface(SPVC_RESOURCE_TYPE_UNIFORM_BUFFER);
|
||||
for (const auto& ubo : ubos) {
|
||||
const Uint32 binding = ubo.location; // GetShaderInterface stores binding in location field
|
||||
if (binding >= m_maxBindings) {
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
if (entry.bindingKinds[binding] == DescriptorBindingKind::None) {
|
||||
entry.bindingKinds[binding] = DescriptorBindingKind::UniformBufferDynamic;
|
||||
}
|
||||
|
||||
// Check for global UBO
|
||||
if (entry.globalUboBinding < 0 &&
|
||||
std::strstr(ubo.name.c_str(), MG_Util::ShaderTranspiler::GLOBAL_UBO_NAME) != nullptr) {
|
||||
entry.globalUboBinding = static_cast<Int>(binding);
|
||||
}
|
||||
}
|
||||
|
||||
// Reflect sampled images
|
||||
auto samplers = session.GetShaderInterface(SPVC_RESOURCE_TYPE_SAMPLED_IMAGE);
|
||||
for (const auto& sampler : samplers) {
|
||||
const Uint32 binding = sampler.location; // GetShaderInterface stores binding in location field
|
||||
if (binding >= m_maxBindings) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Sampler always wins over UBO for a binding slot
|
||||
entry.bindingKinds[binding] = DescriptorBindingKind::CombinedImageSampler;
|
||||
|
||||
// Resolve uniform location for this sampler
|
||||
String uniformName = sampler.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;
|
||||
}
|
||||
|
||||
applyBindings(SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, DescriptorBindingKind::UniformBufferDynamic);
|
||||
applyBindings(SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, DescriptorBindingKind::CombinedImageSampler);
|
||||
|
||||
spvc_context_destroy(context);
|
||||
entry.samplerUniformLocationByBinding[binding] = location;
|
||||
entry.samplerTextureTargetByBinding[binding] =
|
||||
UniformTypeToTextureTarget(program.GetUniformType(static_cast<Uint>(location)));
|
||||
}
|
||||
}
|
||||
|
||||
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()) {
|
||||
// Build Vulkan descriptor set layout and pipeline layout from reflected binding kinds
|
||||
Vector<VkDescriptorSetLayoutBinding> bindings;
|
||||
bindings.reserve(m_maxBindings);
|
||||
for (Uint32 binding = 0; binding < m_maxBindings; ++binding) {
|
||||
const auto kind = entry.bindingKinds[binding];
|
||||
if (kind == DescriptorBindingKind::None) {
|
||||
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;
|
||||
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;
|
||||
entry.dynamicBindings.push_back(binding);
|
||||
} else {
|
||||
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
}
|
||||
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);
|
||||
bindings.push_back(layoutBinding);
|
||||
}
|
||||
|
||||
return true;
|
||||
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, &entry.descriptorSetLayout),
|
||||
"ProgramFactory::ReflectLayout, vkCreateDescriptorSetLayout");
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
|
||||
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
pipelineLayoutInfo.setLayoutCount = 1;
|
||||
pipelineLayoutInfo.pSetLayouts = &entry.descriptorSetLayout;
|
||||
VK_VERIFY(vkCreatePipelineLayout(m_device, &pipelineLayoutInfo, nullptr, &entry.pipelineLayout),
|
||||
"ProgramFactory::ReflectLayout, vkCreatePipelineLayout");
|
||||
}
|
||||
|
||||
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(
|
||||
const ProgramFactory::VkProgramObject& ProgramFactory::GetOrCreateProgram(
|
||||
const MG_State::GLState::ProgramObject& program, CompileOptionFlags flags) {
|
||||
auto hash = ComputeHash(program, flags);
|
||||
auto it = m_cache.find(hash);
|
||||
if (it != m_cache.end()) {
|
||||
return it->second.stages;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
auto& entry = m_cache[hash];
|
||||
@@ -664,88 +568,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
entry.stages.push_back(stage);
|
||||
}
|
||||
|
||||
return entry.stages;
|
||||
}
|
||||
// Reflect and create layout as part of the program object
|
||||
ReflectLayout(program, entry);
|
||||
|
||||
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();
|
||||
return entry;
|
||||
}
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -39,6 +39,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
HashType hash = 0;
|
||||
Vector<VkPipelineShaderStageCreateInfo> stages;
|
||||
Vector<VkShaderModule> modules;
|
||||
|
||||
// Layout data (previously in separate VkProgramLayout)
|
||||
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;
|
||||
|
||||
static inline VkDevice s_device = VK_NULL_HANDLE;
|
||||
|
||||
VkProgramObject() = default;
|
||||
@@ -48,76 +58,86 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
hash = other.hash;
|
||||
stages = std::move(other.stages);
|
||||
modules = std::move(other.modules);
|
||||
descriptorSetLayout = other.descriptorSetLayout;
|
||||
pipelineLayout = other.pipelineLayout;
|
||||
bindingKinds = std::move(other.bindingKinds);
|
||||
dynamicBindings = std::move(other.dynamicBindings);
|
||||
samplerUniformLocationByBinding = std::move(other.samplerUniformLocationByBinding);
|
||||
samplerTextureTargetByBinding = std::move(other.samplerTextureTargetByBinding);
|
||||
globalUboBinding = other.globalUboBinding;
|
||||
other.hash = 0;
|
||||
other.descriptorSetLayout = VK_NULL_HANDLE;
|
||||
other.pipelineLayout = VK_NULL_HANDLE;
|
||||
other.globalUboBinding = -1;
|
||||
}
|
||||
VkProgramObject& operator=(VkProgramObject&& other) noexcept {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
DestroyModules();
|
||||
stages.clear();
|
||||
Destroy();
|
||||
hash = other.hash;
|
||||
stages = std::move(other.stages);
|
||||
modules = std::move(other.modules);
|
||||
descriptorSetLayout = other.descriptorSetLayout;
|
||||
pipelineLayout = other.pipelineLayout;
|
||||
bindingKinds = std::move(other.bindingKinds);
|
||||
dynamicBindings = std::move(other.dynamicBindings);
|
||||
samplerUniformLocationByBinding = std::move(other.samplerUniformLocationByBinding);
|
||||
samplerTextureTargetByBinding = std::move(other.samplerTextureTargetByBinding);
|
||||
globalUboBinding = other.globalUboBinding;
|
||||
other.hash = 0;
|
||||
other.descriptorSetLayout = VK_NULL_HANDLE;
|
||||
other.pipelineLayout = VK_NULL_HANDLE;
|
||||
other.globalUboBinding = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~VkProgramObject() {
|
||||
DestroyModules();
|
||||
stages.clear();
|
||||
Destroy();
|
||||
}
|
||||
|
||||
private:
|
||||
void DestroyModules() {
|
||||
for (auto module : modules) {
|
||||
if (module != VK_NULL_HANDLE && s_device != VK_NULL_HANDLE) {
|
||||
vkDestroyShaderModule(s_device, module, nullptr);
|
||||
void Destroy() {
|
||||
if (s_device != VK_NULL_HANDLE) {
|
||||
if (pipelineLayout != VK_NULL_HANDLE) {
|
||||
vkDestroyPipelineLayout(s_device, pipelineLayout, nullptr);
|
||||
pipelineLayout = VK_NULL_HANDLE;
|
||||
}
|
||||
if (descriptorSetLayout != VK_NULL_HANDLE) {
|
||||
vkDestroyDescriptorSetLayout(s_device, descriptorSetLayout, nullptr);
|
||||
descriptorSetLayout = VK_NULL_HANDLE;
|
||||
}
|
||||
for (auto module : modules) {
|
||||
if (module != VK_NULL_HANDLE) {
|
||||
vkDestroyShaderModule(s_device, module, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
modules.clear();
|
||||
stages.clear();
|
||||
}
|
||||
};
|
||||
|
||||
struct VkProgramLayout {
|
||||
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;
|
||||
}
|
||||
~ProgramFactory();
|
||||
~ProgramFactory() = default;
|
||||
ProgramFactory(const ProgramFactory&) = delete;
|
||||
|
||||
HashType ComputeHash(const MG_State::GLState::ProgramObject& program, CompileOptionFlags flags) const;
|
||||
Vector<VkPipelineShaderStageCreateInfo>& GetOrCreatePipelineShaderStages(
|
||||
const VkProgramObject& GetOrCreateProgram(
|
||||
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);
|
||||
|
||||
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();
|
||||
void ReflectLayout(const MG_State::GLState::ProgramObject& program, VkProgramObject& entry) const;
|
||||
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
Uint32 m_maxBindings = 0;
|
||||
UnorderedMap<HashType, VkProgramObject> m_cache;
|
||||
UnorderedMap<HashType, VkProgramLayout> m_layoutCache;
|
||||
const VulkanRendererConfig& m_config;
|
||||
static inline XXH64_state_t* m_hashState = XXH64_createState();
|
||||
};
|
||||
|
||||
@@ -158,18 +158,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
Bool UniformManager::ResolveSamplerDescriptor(VkCommandBuffer commandBuffer,
|
||||
const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramFactory::VkProgramLayout& layout,
|
||||
Uint32 binding, VkDescriptorImageInfo& outImageInfo) const {
|
||||
const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramFactory::VkProgramObject& programObj,
|
||||
Uint32 binding, VkDescriptorImageInfo& outImageInfo) const {
|
||||
(void)commandBuffer;
|
||||
MOBILEGL_ASSERT(m_textureManager != nullptr, "ResolveSamplerDescriptor: texture manager is null");
|
||||
MOBILEGL_ASSERT(m_samplerManager != nullptr, "ResolveSamplerDescriptor: sampler manager is null");
|
||||
SharedPtr<MG_State::GLState::ITextureObject> texture;
|
||||
if (!ResolveSamplerTexture(program, layout, binding, texture)) {
|
||||
if (!ResolveSamplerTexture(program, programObj, binding, texture)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Int location = layout.samplerUniformLocationByBinding[binding];
|
||||
const Int location = programObj.samplerUniformLocationByBinding[binding];
|
||||
const Int unit = program.GetUniformSamplerOrImageUnitIndex(static_cast<Uint>(location));
|
||||
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
|
||||
const auto samplerOverride = textureUnit.GetSamplerObject();
|
||||
@@ -236,14 +236,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
Bool UniformManager::ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramFactory::VkProgramLayout& layout, Uint32 binding,
|
||||
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) const {
|
||||
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) const {
|
||||
outTexture.reset();
|
||||
if (!MG_State::pGLContext || binding >= layout.samplerUniformLocationByBinding.size()) {
|
||||
if (!MG_State::pGLContext || binding >= programObj.samplerUniformLocationByBinding.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Int location = layout.samplerUniformLocationByBinding[binding];
|
||||
const Int location = programObj.samplerUniformLocationByBinding[binding];
|
||||
if (location < 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -254,29 +254,25 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
|
||||
const TextureTarget preferredTarget = layout.samplerTextureTargetByBinding[binding];
|
||||
const TextureTarget preferredTarget = programObj.samplerTextureTargetByBinding[binding];
|
||||
outTexture = textureUnit.GetBindingSlot(preferredTarget).GetBoundObject();
|
||||
return outTexture != nullptr;
|
||||
}
|
||||
|
||||
Bool UniformManager::CollectSampledTextures(const MG_State::GLState::ProgramObject& program,
|
||||
Vector<MG_State::GLState::ITextureObject*>& outTextures) {
|
||||
const ProgramFactory::VkProgramObject& programObj,
|
||||
Vector<MG_State::GLState::ITextureObject*>& outTextures) {
|
||||
outTextures.clear();
|
||||
MOBILEGL_ASSERT(m_programFactory != nullptr, "CollectSampledTextures: program factory is null");
|
||||
const auto* layout = m_programFactory->GetOrCreateProgramLayout(program);
|
||||
if (layout == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Uint32 bindingCount =
|
||||
std::min<Uint32>(m_maxBindings, static_cast<Uint32>(layout->bindingKinds.size()));
|
||||
std::min<Uint32>(m_maxBindings, static_cast<Uint32>(programObj.bindingKinds.size()));
|
||||
for (Uint32 binding = 0; binding < bindingCount; ++binding) {
|
||||
if (layout->bindingKinds[binding] != ProgramFactory::DescriptorBindingKind::CombinedImageSampler) {
|
||||
if (programObj.bindingKinds[binding] != ProgramFactory::DescriptorBindingKind::CombinedImageSampler) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SharedPtr<MG_State::GLState::ITextureObject> texture;
|
||||
if (!ResolveSamplerTexture(program, *layout, binding, texture) || !texture) {
|
||||
if (!ResolveSamplerTexture(program, programObj, binding, texture) || !texture) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -406,13 +402,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return true;
|
||||
}
|
||||
|
||||
VkResult UniformManager::AllocateDescriptorSetsFromActivePool(Uint32 frameIndex, const ProgramFactory::VkProgramLayout& layout, VkDescriptorSet& outDescriptorSet) {
|
||||
VkResult UniformManager::AllocateDescriptorSetsFromActivePool(Uint32 frameIndex, const ProgramFactory::VkProgramObject& programObj, VkDescriptorSet& outDescriptorSet) {
|
||||
auto& frame = m_frames[frameIndex];
|
||||
auto& bucket = frame.descriptorPools[frame.activeDescriptorPoolIndex];
|
||||
VkDescriptorSetAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
allocInfo.descriptorSetCount = 1;
|
||||
allocInfo.pSetLayouts = &layout.descriptorSetLayout;
|
||||
allocInfo.pSetLayouts = &programObj.descriptorSetLayout;
|
||||
|
||||
allocInfo.descriptorPool = bucket.handle;
|
||||
VkResult result = vkAllocateDescriptorSets(m_device, &allocInfo, &outDescriptorSet);
|
||||
@@ -426,14 +422,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
Bool UniformManager::BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
||||
const MG_State::GLState::ProgramObject& program,
|
||||
Uint32 frameIndex,
|
||||
const SamplerBindingOverride* samplerBindingOverride) {
|
||||
MOBILEGL_ASSERT(m_programFactory != nullptr, "BindProgramUniformBuffers: program factory is null");
|
||||
const auto* layout = m_programFactory->GetOrCreateProgramLayout(program);
|
||||
MOBILEGL_ASSERT(layout != nullptr,
|
||||
"UniformDescriptorBinder::BindProgramUniformBuffers: program layout is null");
|
||||
|
||||
const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramFactory::VkProgramObject& programObj,
|
||||
Uint32 frameIndex,
|
||||
const SamplerBindingOverride* samplerBindingOverride) {
|
||||
auto& frame = m_frames[frameIndex];
|
||||
if (frame.descriptorPools.empty()) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: frame descriptor pools are invalid");
|
||||
@@ -444,13 +436,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
|
||||
VkResult allocResult = AllocateDescriptorSetsFromActivePool(frameIndex, *layout, descriptorSet);
|
||||
VkResult allocResult = AllocateDescriptorSetsFromActivePool(frameIndex, programObj, descriptorSet);
|
||||
if (allocResult == VK_ERROR_OUT_OF_POOL_MEMORY || allocResult == VK_ERROR_FRAGMENTED_POOL) {
|
||||
if (!GrowFrameDescriptorPool(frame, frameIndex)) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: descriptor pool growth failed");
|
||||
return false;
|
||||
}
|
||||
allocResult = AllocateDescriptorSetsFromActivePool(frameIndex, *layout, descriptorSet);
|
||||
allocResult = AllocateDescriptorSetsFromActivePool(frameIndex, programObj, descriptorSet);
|
||||
}
|
||||
if (allocResult != VK_SUCCESS || descriptorSet == VK_NULL_HANDLE) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: vkAllocateDescriptorSets returned %d",
|
||||
@@ -476,12 +468,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Vector<Uint32> dynamicOffsets;
|
||||
bufferInfos.reserve(m_maxBindings);
|
||||
imageInfos.reserve(m_maxBindings);
|
||||
dynamicOffsets.reserve(layout->dynamicBindings.size());
|
||||
dynamicOffsets.reserve(programObj.dynamicBindings.size());
|
||||
|
||||
const Uint32 bindingCount =
|
||||
std::min<Uint32>(m_maxBindings, static_cast<Uint32>(layout->bindingKinds.size()));
|
||||
std::min<Uint32>(m_maxBindings, static_cast<Uint32>(programObj.bindingKinds.size()));
|
||||
for (Uint32 binding = 0; binding < bindingCount; ++binding) {
|
||||
const auto kind = layout->bindingKinds[binding];
|
||||
const auto kind = programObj.bindingKinds[binding];
|
||||
if (kind == ProgramFactory::DescriptorBindingKind::None) {
|
||||
continue;
|
||||
}
|
||||
@@ -497,7 +489,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const void* payload = bindingData[binding];
|
||||
VkDeviceSize payloadSize = bindingSizes[binding];
|
||||
if (payload == nullptr || payloadSize == 0) {
|
||||
if (layout->globalUboBinding == static_cast<Int>(binding)) {
|
||||
if (programObj.globalUboBinding == static_cast<Int>(binding)) {
|
||||
const void* globalUboData = program.GetUBOData();
|
||||
const VkDeviceSize globalUboSize = static_cast<VkDeviceSize>(program.GetUBOSize());
|
||||
if (globalUboData != nullptr && globalUboSize > 0) {
|
||||
@@ -510,7 +502,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
BufferSlice slice{};
|
||||
if (!m_bufferManager->UploadTransient(BufferKind::Uniform, frameIndex, payload, payloadSize,
|
||||
m_minDynamicOffsetAlignment, slice)) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: UBO upload failed on binding %u",
|
||||
MOBILEGL_ASSERT(false, "UniformDescriptorBinder::BindProgramUniformBuffers failed: UBO upload failed on binding %u",
|
||||
binding);
|
||||
return false;
|
||||
}
|
||||
@@ -534,7 +526,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
samplerBindingOverride->sampler != nullptr) {
|
||||
hasImage = ResolveSamplerDescriptorOverride(*samplerBindingOverride, imageInfo);
|
||||
} else {
|
||||
hasImage = ResolveSamplerDescriptor(commandBuffer, program, *layout, binding, imageInfo);
|
||||
hasImage = ResolveSamplerDescriptor(commandBuffer, program, programObj, binding, imageInfo);
|
||||
}
|
||||
if (!hasImage) {
|
||||
MGLOG_E("UniformDescriptorBinder::BindProgramUniformBuffers failed: sampler binding %u has no valid texture descriptor",
|
||||
@@ -557,7 +549,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
vkUpdateDescriptorSets(m_device, static_cast<Uint32>(writes.size()), writes.data(), 0, nullptr);
|
||||
}
|
||||
|
||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, layout->pipelineLayout, 0, 1,
|
||||
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, programObj.pipelineLayout, 0, 1,
|
||||
&descriptorSet, static_cast<Uint32>(dynamicOffsets.size()), dynamicOffsets.data());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -39,9 +39,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
void BeginFrame(Uint32 frameIndex);
|
||||
Bool CollectSampledTextures(const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramFactory::VkProgramObject& programObj,
|
||||
Vector<MG_State::GLState::ITextureObject*>& outTextures);
|
||||
Bool BindProgramUniformBuffers(VkCommandBuffer commandBuffer,
|
||||
const MG_State::GLState::ProgramObject& program, Uint32 frameIndex,
|
||||
const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramFactory::VkProgramObject& programObj,
|
||||
Uint32 frameIndex,
|
||||
const SamplerBindingOverride* samplerBindingOverride = nullptr);
|
||||
|
||||
private:
|
||||
@@ -59,10 +62,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
};
|
||||
|
||||
Bool ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramFactory::VkProgramLayout& layout, Uint32 binding,
|
||||
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||
SharedPtr<MG_State::GLState::ITextureObject>& outTexture) const;
|
||||
Bool ResolveSamplerDescriptor(VkCommandBuffer commandBuffer, const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramFactory::VkProgramLayout& layout, Uint32 binding,
|
||||
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||
VkDescriptorImageInfo& outImageInfo) const;
|
||||
Bool ResolveSamplerDescriptorOverride(const SamplerBindingOverride& samplerBindingOverride,
|
||||
VkDescriptorImageInfo& outImageInfo) const;
|
||||
@@ -71,7 +74,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool CreateDescriptorPool(Uint32 maxSets, VkDescriptorPool& outPool) const;
|
||||
Bool GrowFrameDescriptorPool(FrameResources& frame, Uint32 frameIndex);
|
||||
VkResult AllocateDescriptorSetsFromActivePool(
|
||||
Uint32 frameIndex, const ProgramFactory::VkProgramLayout& layout, VkDescriptorSet& outDescriptorSet);
|
||||
Uint32 frameIndex, const ProgramFactory::VkProgramObject& programObj, VkDescriptorSet& outDescriptorSet);
|
||||
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
VkBufferManager* m_bufferManager = nullptr;
|
||||
|
||||
@@ -472,7 +472,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
if (!m_bufferManager.UploadTransient(BufferKind::Vertex, m_frameContext.GetCurrentFrameIndex(),
|
||||
sourceData->data(), static_cast<VkDeviceSize>(sourceSize), 16,
|
||||
slice)) {
|
||||
MGLOG_E("UploadAndBindVertexStreams skipped: failed to upload transient binding %zu", binding);
|
||||
MOBILEGL_ASSERT(false, "UploadAndBindVertexStreams skipped: failed to upload transient binding %zu", binding);
|
||||
return false;
|
||||
}
|
||||
if (!transientThisFrame) {
|
||||
@@ -534,7 +534,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
if (!m_bufferManager.UploadTransient(BufferKind::Index, m_frameContext.GetCurrentFrameIndex(),
|
||||
indexData->data() + pIndexBufferView->indexByteOffset,
|
||||
static_cast<VkDeviceSize>(indexDataSizeBytes), indexSize, slice)) {
|
||||
MGLOG_E("DrawElements skipped: failed to prepare transient index buffer");
|
||||
MOBILEGL_ASSERT(false, "DrawElements skipped: failed to prepare transient index buffer");
|
||||
return false;
|
||||
}
|
||||
if (!transientThisFrame) {
|
||||
@@ -667,11 +667,11 @@ void main() {
|
||||
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO
|
||||
};
|
||||
ProgramFactory::CompileOptionFlags transformFlags = 0;
|
||||
auto& stages = m_programFactory->GetOrCreatePipelineShaderStages(*m_blitResources.program, transformFlags);
|
||||
const auto& programObj = m_programFactory->GetOrCreateProgram(*m_blitResources.program, transformFlags);
|
||||
PipelineFactory::PipelineCreatePayload payload{
|
||||
.programHash = m_programFactory->ComputeHash(*m_blitResources.program, transformFlags),
|
||||
.programHash = programObj.hash,
|
||||
.vertexInputHash = 0,
|
||||
.pipelineLayout = m_programFactory->GetOrCreatePipelineLayout(*m_blitResources.program),
|
||||
.pipelineLayout = programObj.pipelineLayout,
|
||||
.renderPass = renderPassEntry.renderPass,
|
||||
.subpass = 0,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
||||
@@ -687,7 +687,7 @@ void main() {
|
||||
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
||||
.stages = &stages,
|
||||
.stages = &programObj.stages,
|
||||
.vertexInputState = &kEmptyVertexInputState
|
||||
};
|
||||
return m_pipelineFactory->GetOrCreatePipeline(payload);
|
||||
@@ -700,16 +700,14 @@ void main() {
|
||||
const RenderPassEntry& renderPassEntry) {
|
||||
ProgramFactory::CompileOptionFlags transformFlags = GetShaderTransformFlags(m_swapchainObject.GetPreTransform());
|
||||
Bool invertClockwise = transformFlags & ProgramFactory::CompileOptionBit::PositionYFlip;
|
||||
auto& stages = m_programFactory->GetOrCreatePipelineShaderStages(program, transformFlags);
|
||||
if (stages.empty()) {
|
||||
const auto& programObj = m_programFactory->GetOrCreateProgram(program, transformFlags);
|
||||
if (programObj.stages.empty()) {
|
||||
MGLOG_D("GetOrCreatePipeline skipped: program has no shader stages");
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
const Uint64 programHash = m_programFactory->ComputeHash(program, transformFlags);
|
||||
|
||||
auto vertexInputHash = m_vertexInputStateFactory->ComputeHash(vao);
|
||||
auto& vis = m_vertexInputStateFactory->GetOrCreateVertexInputState(vao);
|
||||
auto pipelineLayout = m_programFactory->GetOrCreatePipelineLayout(program);
|
||||
auto cullFaceEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::CullFace);
|
||||
auto depthTestEnabled = MG_State::pGLContext->IsCapabilityEnabled(CapabilityInput::DepthTest);
|
||||
BlendFactor srcRGB = BlendFactor::One;
|
||||
@@ -720,9 +718,9 @@ void main() {
|
||||
auto mask = MG_State::pGLContext->GetColorMask();
|
||||
|
||||
PipelineFactory::PipelineCreatePayload payload {
|
||||
.programHash = programHash,
|
||||
.programHash = programObj.hash,
|
||||
.vertexInputHash = vertexInputHash,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
.pipelineLayout = programObj.pipelineLayout,
|
||||
.renderPass = renderPassEntry.renderPass,
|
||||
.subpass = 0,
|
||||
.topology = MG_Util::ConvertPrimitiveModeToVkEnum(mode),
|
||||
@@ -743,7 +741,7 @@ void main() {
|
||||
(mask.g() ? VK_COLOR_COMPONENT_G_BIT : 0u) |
|
||||
(mask.b() ? VK_COLOR_COMPONENT_B_BIT : 0u) |
|
||||
(mask.a() ? VK_COLOR_COMPONENT_A_BIT : 0u) ),
|
||||
.stages = &stages,
|
||||
.stages = &programObj.stages,
|
||||
.vertexInputState = &vis.state
|
||||
};
|
||||
return m_pipelineFactory->GetOrCreatePipeline(payload);
|
||||
@@ -756,6 +754,8 @@ void main() {
|
||||
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||
const auto& vao = *MG_State::pGLContext->GetBoundVertexArray();
|
||||
const auto& program = *MG_State::pGLContext->GetCurrentProgram();
|
||||
ProgramFactory::CompileOptionFlags transformFlags = GetShaderTransformFlags(m_swapchainObject.GetPreTransform());
|
||||
const auto& programObj = m_programFactory->GetOrCreateProgram(program, transformFlags);
|
||||
|
||||
// Begin command recording if not yet
|
||||
if (!frame.isCommandRecording) {
|
||||
@@ -770,7 +770,7 @@ void main() {
|
||||
// without draws in between to give it a chance to materialize such clear.
|
||||
// Deal with this situation here.
|
||||
Vector<MG_State::GLState::ITextureObject*> sampledTextures;
|
||||
Bool hasSampledTextures = m_uniformManager->CollectSampledTextures(program, sampledTextures);
|
||||
Bool hasSampledTextures = m_uniformManager->CollectSampledTextures(program, programObj, sampledTextures);
|
||||
MOBILEGL_ASSERT(hasSampledTextures, "%s: CollectSampledTextures failed", __func__);
|
||||
MGLOG_D("SetupDraw: program=%u drawFbo=%u sampledTextureCount=%zu activeRenderPass=%s",
|
||||
program.GetExternalIndex(), drawFbo ? drawFbo->GetExternalIndex() : 0u, sampledTextures.size(),
|
||||
@@ -856,7 +856,7 @@ void main() {
|
||||
|
||||
vkCmdBindPipeline(frame.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
|
||||
m_uniformManager->BindProgramUniformBuffers(frame.commandBuffer, program,
|
||||
m_uniformManager->BindProgramUniformBuffers(frame.commandBuffer, program, programObj,
|
||||
m_frameContext.GetCurrentFrameIndex());
|
||||
|
||||
auto vtxUploadOk = UploadAndBindVertexBuffers(frame.commandBuffer, vao);
|
||||
@@ -1086,8 +1086,10 @@ void main() {
|
||||
.sampler = (filter == GL_LINEAR ? m_blitResources.linearSampler.get()
|
||||
: m_blitResources.nearestSampler.get()),
|
||||
};
|
||||
ProgramFactory::CompileOptionFlags blitTransformFlags = 0;
|
||||
const auto& blitProgramObj = m_programFactory->GetOrCreateProgram(*m_blitResources.program, blitTransformFlags);
|
||||
const Bool bound = m_uniformManager->BindProgramUniformBuffers(
|
||||
frame.commandBuffer, *m_blitResources.program, m_frameContext.GetCurrentFrameIndex(),
|
||||
frame.commandBuffer, *m_blitResources.program, blitProgramObj, m_frameContext.GetCurrentFrameIndex(),
|
||||
&samplerBindingOverride);
|
||||
MOBILEGL_ASSERT(bound, "TryBlitToDefaultFramebufferWithShader: BindProgramUniformBuffers failed");
|
||||
vkCmdDraw(frame.commandBuffer, 3, 1, 0, 0);
|
||||
|
||||
@@ -179,7 +179,14 @@ namespace MobileGL {
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
if (bindings[i]->descriptor_type == SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER) {
|
||||
InterfaceVariable var;
|
||||
var.name = bindings[i]->name;
|
||||
// Use the block/type name (e.g. "MGL_GLOBAL_UBO") rather than
|
||||
// the variable name, which may be empty or meaningless for UBOs.
|
||||
// This is consistent with ParseMetaData() which uses type_description->type_name.
|
||||
if (bindings[i]->type_description && bindings[i]->type_description->type_name) {
|
||||
var.name = bindings[i]->type_description->type_name;
|
||||
} else {
|
||||
var.name = bindings[i]->name;
|
||||
}
|
||||
var.location = bindings[i]->binding;
|
||||
variables.push_back(var);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user