[Feat] (MG_Backend/DirectVulkan): get real maxProgramBindings from VkDevice

This commit is contained in:
2026-05-05 13:19:45 +08:00
parent 1bf12be278
commit 94e93b171c
@@ -107,7 +107,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
namespace { namespace {
static constexpr Uint32 kMaxProgramBindings = 16;
static constexpr Uint32 kDescriptorSetsPerFrame = 64; 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;
@@ -132,6 +131,26 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const char* label = nullptr; const char* label = nullptr;
}; };
static Uint32 ComputeMaxProgramBindings(const VkPhysicalDeviceProperties& properties) {
const auto& limits = properties.limits;
static constexpr Uint32 kMinProgramBindings = 16;
static constexpr Uint32 kMaxProgramBindingsCap = 256;
const Uint32 maxCombinedImageSamplers =
std::min(limits.maxPerStageDescriptorSamplers, limits.maxDescriptorSetSamplers);
const Uint32 maxSampledImages =
std::min(limits.maxPerStageDescriptorSampledImages, limits.maxDescriptorSetSampledImages);
const Uint32 maxDynamicUniformBuffers =
std::min(limits.maxPerStageDescriptorUniformBuffers, limits.maxDescriptorSetUniformBuffersDynamic);
Uint32 maxBindings = limits.maxPerStageResources;
maxBindings = std::min(maxBindings, maxCombinedImageSamplers);
maxBindings = std::min(maxBindings, maxSampledImages + maxDynamicUniformBuffers);
maxBindings = std::max(kMinProgramBindings, maxBindings);
maxBindings = std::min(kMaxProgramBindingsCap, maxBindings);
return maxBindings;
}
static void GetImageTransitionSourceState(VkImageLayout oldLayout, VkPipelineStageFlags& outSrcStageMask, static void GetImageTransitionSourceState(VkImageLayout oldLayout, VkPipelineStageFlags& outSrcStageMask,
VkAccessFlags& outSrcAccessMask) { VkAccessFlags& outSrcAccessMask) {
switch (oldLayout) { switch (oldLayout) {
@@ -420,11 +439,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
succeeded = m_renderPassManager->Initialize(); succeeded = m_renderPassManager->Initialize();
MOBILEGL_ASSERT(succeeded, "VkRenderPassManager initialization failed."); MOBILEGL_ASSERT(succeeded, "VkRenderPassManager initialization failed.");
const Uint32 maxProgramBindings = ComputeMaxProgramBindings(m_physicalDevice.properties);
MGLOG_I("DirectVulkan: using %u program descriptor bindings", maxProgramBindings);
RecreateSwapchain(); RecreateSwapchain();
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, kMaxProgramBindings); m_programFactory = MakeUnique<ProgramFactory>(m_device, m_config, maxProgramBindings);
MOBILEGL_ASSERT(m_programFactory != nullptr, "ProgramFactory creation failed."); MOBILEGL_ASSERT(m_programFactory != nullptr, "ProgramFactory creation failed.");
m_samplerManager = MakeUnique<VkSamplerManager>(); m_samplerManager = MakeUnique<VkSamplerManager>();
@@ -439,7 +461,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
succeeded = m_uniformManager->Initialize( succeeded = m_uniformManager->Initialize(
m_device, &m_bufferManager, m_programFactory.get(), m_device, &m_bufferManager, m_programFactory.get(),
m_physicalDevice.properties.limits.minUniformBufferOffsetAlignment, m_config.MaxFramesInFlight, m_physicalDevice.properties.limits.minUniformBufferOffsetAlignment, m_config.MaxFramesInFlight,
kMaxProgramBindings, kDescriptorSetsPerFrame, m_textureManager.get(), m_samplerManager.get()); maxProgramBindings, 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.");
@@ -1653,7 +1675,9 @@ void main() {
void VulkanRenderer::DrawArrays(const DrawCmd& payload) { void VulkanRenderer::DrawArrays(const DrawCmd& payload) {
auto& frame = m_frameContext.GetCurrent(); auto& frame = m_frameContext.GetCurrent();
SetupDraw(frame, payload.mode, 0); if (!SetupDraw(frame, payload.mode, 0)) {
return;
}
MOBILEGL_ASSERT(frame.isCommandRecording, "%s: frame recording was not started", __func__); MOBILEGL_ASSERT(frame.isCommandRecording, "%s: frame recording was not started", __func__);
@@ -1669,8 +1693,10 @@ void main() {
void VulkanRenderer::DrawElements(const DrawIndexedCmd& payload) { void VulkanRenderer::DrawElements(const DrawIndexedCmd& payload) {
auto& frame = m_frameContext.GetCurrent(); auto& frame = m_frameContext.GetCurrent();
SetupDraw(frame, payload.mode, DrawSetupAspect::IndexBuffer, if (!SetupDraw(frame, payload.mode, DrawSetupAspect::IndexBuffer,
&payload.indexBufferView); &payload.indexBufferView)) {
return;
}
MOBILEGL_ASSERT(frame.isCommandRecording, "%s: frame recording was not started", __func__); MOBILEGL_ASSERT(frame.isCommandRecording, "%s: frame recording was not started", __func__);
@@ -1687,8 +1713,10 @@ void main() {
void VulkanRenderer::MultiDrawElements(const MultiDrawIndexedCmd& payload) { void VulkanRenderer::MultiDrawElements(const MultiDrawIndexedCmd& payload) {
auto& frame = m_frameContext.GetCurrent(); auto& frame = m_frameContext.GetCurrent();
SetupDraw(frame, payload.mode, DrawSetupAspect::IndexBuffer, if (!SetupDraw(frame, payload.mode, DrawSetupAspect::IndexBuffer,
&payload.indexBufferView); &payload.indexBufferView)) {
return;
}
MOBILEGL_ASSERT(frame.isCommandRecording, "%s: frame recording was not started", __func__); MOBILEGL_ASSERT(frame.isCommandRecording, "%s: frame recording was not started", __func__);