[Fix] (GL): report tessellation-stage image uniform limits from the backend and enforce them at link

This commit is contained in:
2026-10-12 08:08:58 -04:00
parent c881bc2396
commit 2eae028938
16 changed files with 156 additions and 12 deletions
+2
View File
@@ -411,6 +411,8 @@ namespace MobileGL {
Int MaxImageUnits = 8;
Int MaxCombinedImageUniforms = 8;
Int MaxVertexImageUniforms = 0;
Int MaxTessControlImageUniforms = 0;
Int MaxTessEvaluationImageUniforms = 0;
Int MaxGeometryImageUniforms = 0;
Int MaxFragmentImageUniforms = 8;
Int MaxComputeImageUniforms = 8;
@@ -1820,6 +1820,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
m_dynamicParameters.MaxCombinedImageUniforms});
};
m_dynamicParameters.MaxVertexImageUniforms = clampStageImageUniforms(m_GLESCapabilities.MaxVertexImageUniforms);
m_dynamicParameters.MaxTessControlImageUniforms =
clampStageImageUniforms(m_GLESCapabilities.MaxTessControlImageUniforms);
m_dynamicParameters.MaxTessEvaluationImageUniforms =
clampStageImageUniforms(m_GLESCapabilities.MaxTessEvaluationImageUniforms);
m_dynamicParameters.MaxGeometryImageUniforms =
clampStageImageUniforms(m_GLESCapabilities.MaxGeometryImageUniforms);
m_dynamicParameters.MaxFragmentImageUniforms =
@@ -11188,6 +11188,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
[[maybe_unused]] Int AdvertisedStageImageUniformLimit(ShaderStage stage) {
switch (stage) {
case ShaderStage::Vertex: return g_GLESCapabilities.MaxVertexImageUniforms;
case ShaderStage::TessControl: return g_GLESCapabilities.MaxTessControlImageUniforms;
case ShaderStage::TessEval: return g_GLESCapabilities.MaxTessEvaluationImageUniforms;
case ShaderStage::Geometry: return g_GLESCapabilities.MaxGeometryImageUniforms;
case ShaderStage::Fragment: return g_GLESCapabilities.MaxFragmentImageUniforms;
case ShaderStage::Compute: return g_GLESCapabilities.MaxComputeImageUniforms;
@@ -1281,6 +1281,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// device reports it, so these are the exact limits the logical device can compile and run.
m_dynamicParameters.MaxVertexImageUniforms =
m_vulkanCaps.SupportsVertexPipelineStoresAndAtomics ? maxPerStageImageUniforms : 0;
// The tessellation stages are vertex-pipeline stages too, so the same feature gates them.
m_dynamicParameters.MaxTessControlImageUniforms = m_dynamicParameters.MaxVertexImageUniforms;
m_dynamicParameters.MaxTessEvaluationImageUniforms = m_dynamicParameters.MaxVertexImageUniforms;
m_dynamicParameters.MaxGeometryImageUniforms =
m_vulkanCaps.SupportsVertexPipelineStoresAndAtomics && m_vulkanCaps.SupportsGeometryShader
? maxPerStageImageUniforms
+6 -2
View File
@@ -2195,10 +2195,14 @@ namespace MobileGL::MG_Impl::GLImpl {
*params = kFrontendMaxTessEvaluationAtomicCounterBuffers;
return;
case GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS:
*params = 0;
*params = MG_Backend::pActiveBackendObject
? MG_Backend::pActiveBackendObject->GetDynamicParameters().MaxTessControlImageUniforms
: MG_Backend::DynamicBackendParameters{}.MaxTessControlImageUniforms;
return;
case GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS:
*params = 0;
*params = MG_Backend::pActiveBackendObject
? MG_Backend::pActiveBackendObject->GetDynamicParameters().MaxTessEvaluationImageUniforms
: MG_Backend::DynamicBackendParameters{}.MaxTessEvaluationImageUniforms;
return;
case GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS:
*params = StageStorageBlockCount(&MG_Backend::DynamicBackendParameters::MaxTessControlShaderStorageBlocks);
+1
View File
@@ -379,6 +379,7 @@
F(MaxComputeWorkGroupCount) F(MaxComputeWorkGroupSize) F(MaxShaderStorageBufferBindings) \
F(MaxTextureBufferSize) F(TextureBufferOffsetAlignment) F(MaxUniformBufferBindings) \
F(MaxUniformBlockSize) F(MaxImageUnits) F(MaxCombinedImageUniforms) F(MaxVertexImageUniforms) \
F(MaxTessControlImageUniforms) F(MaxTessEvaluationImageUniforms) \
F(MaxGeometryImageUniforms) F(MaxFragmentImageUniforms) F(MaxComputeImageUniforms) \
F(MaxDrawBuffers) F(MaxColorAttachments) F(MaxClipDistances) F(MaxCullDistances) \
F(MaxCombinedClipAndCullDistances) F(MaxViewports) F(LayerProvokingVertex) \
@@ -632,6 +632,8 @@ inline constexpr WireLayoutMember kMGPipeWireLayoutMembers[] = {
{"DynamicBackendParameters.MaxImageUnits", offsetof(DynamicBackendParameters, MaxImageUnits), sizeof(((DynamicBackendParameters*)nullptr)->MaxImageUnits)},
{"DynamicBackendParameters.MaxCombinedImageUniforms", offsetof(DynamicBackendParameters, MaxCombinedImageUniforms), sizeof(((DynamicBackendParameters*)nullptr)->MaxCombinedImageUniforms)},
{"DynamicBackendParameters.MaxVertexImageUniforms", offsetof(DynamicBackendParameters, MaxVertexImageUniforms), sizeof(((DynamicBackendParameters*)nullptr)->MaxVertexImageUniforms)},
{"DynamicBackendParameters.MaxTessControlImageUniforms", offsetof(DynamicBackendParameters, MaxTessControlImageUniforms), sizeof(((DynamicBackendParameters*)nullptr)->MaxTessControlImageUniforms)},
{"DynamicBackendParameters.MaxTessEvaluationImageUniforms", offsetof(DynamicBackendParameters, MaxTessEvaluationImageUniforms), sizeof(((DynamicBackendParameters*)nullptr)->MaxTessEvaluationImageUniforms)},
{"DynamicBackendParameters.MaxGeometryImageUniforms", offsetof(DynamicBackendParameters, MaxGeometryImageUniforms), sizeof(((DynamicBackendParameters*)nullptr)->MaxGeometryImageUniforms)},
{"DynamicBackendParameters.MaxFragmentImageUniforms", offsetof(DynamicBackendParameters, MaxFragmentImageUniforms), sizeof(((DynamicBackendParameters*)nullptr)->MaxFragmentImageUniforms)},
{"DynamicBackendParameters.MaxComputeImageUniforms", offsetof(DynamicBackendParameters, MaxComputeImageUniforms), sizeof(((DynamicBackendParameters*)nullptr)->MaxComputeImageUniforms)},
@@ -255,9 +255,9 @@ namespace {
// its linker never counts uniforms against them - so a program declaring one image uniform
// more than the limit linked cleanly and then rendered nothing.
//
// The limits are the ones glGetIntegerv answers (MG_Impl/GLImpl/Getter/GL_Getter.cpp), the
// hardcoded tessellation zeros included: a program may not exceed a limit the implementation
// advertises, whatever the driver underneath would have taken.
// The limits are the ones glGetIntegerv answers (MG_Impl/GLImpl/Getter/GL_Getter.cpp): a
// program may not exceed a limit the implementation advertises, whatever the driver
// underneath would have taken.
//
// Counts the APPLICATION's image uniforms. The DirectGLES read/write split emits a second
// declaration for an image a stage both reads and writes (MG_Backend/DirectGLES/Utils.h), but
@@ -279,8 +279,8 @@ namespace {
"GL_MAX_FRAGMENT_IMAGE_UNIFORMS", "GL_MAX_COMPUTE_IMAGE_UNIFORMS"};
constexpr SizeT kStageCount = sizeof(kStages) / sizeof(kStages[0]);
const Int limits[kStageCount] = {env.params.MaxVertexImageUniforms,
0,
0,
env.params.MaxTessControlImageUniforms,
env.params.MaxTessEvaluationImageUniforms,
env.params.MaxGeometryImageUniforms,
env.params.MaxFragmentImageUniforms,
env.params.MaxComputeImageUniforms};
@@ -46,6 +46,8 @@ namespace {
GLint glesMinorVersion = 1;
GLint maxVertexImageUniforms = 2;
GLint maxGeometryImageUniforms = 3;
GLint maxTessControlImageUniforms = 6;
GLint maxTessEvaluationImageUniforms = 7;
GLint maxFragmentImageUniforms = 4;
GLint maxComputeImageUniforms = 5;
bool maxGeometryImageUniformsQueried = false;
@@ -194,6 +196,14 @@ namespace {
g_fake.maxGeometryImageUniformsQueried = true;
*data = g_fake.maxGeometryImageUniforms;
break;
case GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS:
g_fake.maxGeometryImageUniformsQueried = true;
*data = g_fake.maxTessControlImageUniforms;
break;
case GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS:
g_fake.maxGeometryImageUniformsQueried = true;
*data = g_fake.maxTessEvaluationImageUniforms;
break;
case GL_MAX_FRAGMENT_IMAGE_UNIFORMS:
*data = g_fake.maxFragmentImageUniforms;
break;
@@ -689,6 +699,8 @@ TEST(ImageUniformCapabilities, QueriesRealPerStageLimitsAndConservativelyGatesGe
ASSERT_TRUE(MobileGL::MG_Util::BackendLoader::FillInGLESCapabilities(es31Caps, funcs));
EXPECT_EQ(es31Caps.MaxVertexImageUniforms, g_fake.maxVertexImageUniforms);
EXPECT_EQ(es31Caps.MaxGeometryImageUniforms, 0);
EXPECT_EQ(es31Caps.MaxTessControlImageUniforms, 0);
EXPECT_EQ(es31Caps.MaxTessEvaluationImageUniforms, 0);
EXPECT_EQ(es31Caps.MaxFragmentImageUniforms, g_fake.maxFragmentImageUniforms);
EXPECT_EQ(es31Caps.MaxComputeImageUniforms, g_fake.maxComputeImageUniforms);
EXPECT_FALSE(g_fake.maxGeometryImageUniformsQueried);
@@ -700,6 +712,8 @@ TEST(ImageUniformCapabilities, QueriesRealPerStageLimitsAndConservativelyGatesGe
ASSERT_TRUE(MobileGL::MG_Util::BackendLoader::FillInGLESCapabilities(es32Caps, funcs));
EXPECT_EQ(es32Caps.MaxVertexImageUniforms, g_fake.maxVertexImageUniforms);
EXPECT_EQ(es32Caps.MaxGeometryImageUniforms, g_fake.maxGeometryImageUniforms);
EXPECT_EQ(es32Caps.MaxTessControlImageUniforms, g_fake.maxTessControlImageUniforms);
EXPECT_EQ(es32Caps.MaxTessEvaluationImageUniforms, g_fake.maxTessEvaluationImageUniforms);
EXPECT_EQ(es32Caps.MaxFragmentImageUniforms, g_fake.maxFragmentImageUniforms);
EXPECT_EQ(es32Caps.MaxComputeImageUniforms, g_fake.maxComputeImageUniforms);
EXPECT_TRUE(g_fake.maxGeometryImageUniformsQueried);
@@ -951,6 +951,71 @@ void main() {
}
}
// The same rule for the tessellation stages, whose limits come from the backend like the
// others (they used to be hard-coded zeros). Sized off the advertised limit for the same
// reason as above: one image over it must fail and name the limit, and exactly at it must
// link whenever the limit is non-zero.
TEST_F(ProgramInterfaceTest, TessellationImageUniformsAreCheckedAgainstTheirOwnLimit) {
GLint maxTesImages = -1;
GetIntegerv(GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS, &maxTesImages);
ASSERT_EQ(TakeError(), GL_NO_ERROR);
ASSERT_GE(maxTesImages, 0);
const auto linkWithTesImages = [](GLint count) {
const std::string n = std::to_string(count);
const std::string tcs = R"(#version 430
layout(vertices = 3) out;
void main() {
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
gl_TessLevelOuter[0] = 1.0; gl_TessLevelOuter[1] = 1.0; gl_TessLevelOuter[2] = 1.0;
gl_TessLevelInner[0] = 1.0;
}
)";
const std::string tes = std::string(R"(#version 430
layout(triangles) in;
layout(r32i) uniform iimage2D u_tesImage[)") + n + R"(];
void main() {
int value = 1;
for (int i = 0; i < )" + n + R"(; ++i) {
value = imageAtomicAdd(u_tesImage[i], ivec2(0), value);
}
gl_Position = gl_in[0].gl_Position * float(value);
}
)";
const GLuint program = CreateProgram();
const auto attach = [program](GLenum stage, const char* source) {
const GLuint sh = CreateShader(stage);
ShaderSource(sh, 1, &source, nullptr);
CompileShader(sh);
GLint compiled = 0;
GetShaderiv(sh, GL_COMPILE_STATUS, &compiled);
EXPECT_EQ(compiled, GL_TRUE) << "stage " << stage << " must compile";
AttachShader(program, sh);
};
attach(GL_VERTEX_SHADER, kSimpleVs);
attach(GL_TESS_CONTROL_SHADER, tcs.c_str());
attach(GL_TESS_EVALUATION_SHADER, tes.c_str());
attach(GL_FRAGMENT_SHADER, kSimpleFs);
LinkProgram(program);
return program;
};
const GLuint over = linkWithTesImages(maxTesImages + 1);
GLint status = -1;
GetProgramiv(over, GL_LINK_STATUS, &status);
EXPECT_EQ(status, GL_FALSE);
char log[4096] = "";
GetProgramInfoLog(over, sizeof(log), nullptr, log);
EXPECT_NE(std::string(log).find("GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS"), std::string::npos)
<< "info log was: " << log;
ClearErrors();
if (maxTesImages > 0) {
ExpectLinked(linkWithTesImages(maxTesImages));
ClearErrors();
}
}
// Uniform blocks are counted the same way, and the synthesized block that carries the
// default-block uniforms is not one of them.
TEST_F(ProgramInterfaceTest, UniformBlocksOverAStageLimitFailToLink) {
+32 -2
View File
@@ -664,6 +664,8 @@ TEST(DirectVulkanSanity, GatesPerStageImageUniformLimitsOnPhysicalDeviceFeatures
const auto& withoutGeometry = backend.GetDynamicParameters();
EXPECT_EQ(withoutGeometry.MaxVertexImageUniforms, 10);
EXPECT_EQ(withoutGeometry.MaxTessControlImageUniforms, 10);
EXPECT_EQ(withoutGeometry.MaxTessEvaluationImageUniforms, 10);
EXPECT_EQ(withoutGeometry.MaxGeometryImageUniforms, 0);
EXPECT_EQ(withoutGeometry.MaxFragmentImageUniforms, 10);
EXPECT_EQ(withoutGeometry.MaxComputeImageUniforms, 9);
@@ -676,6 +678,8 @@ TEST(DirectVulkanSanity, GatesPerStageImageUniformLimitsOnPhysicalDeviceFeatures
caps.SupportsFragmentStoresAndAtomics = false;
backend.ApplyVulkanCapabilitiesForTesting(caps);
EXPECT_EQ(backend.GetDynamicParameters().MaxVertexImageUniforms, 0);
EXPECT_EQ(backend.GetDynamicParameters().MaxTessControlImageUniforms, 0);
EXPECT_EQ(backend.GetDynamicParameters().MaxTessEvaluationImageUniforms, 0);
EXPECT_EQ(backend.GetDynamicParameters().MaxGeometryImageUniforms, 0);
EXPECT_EQ(backend.GetDynamicParameters().MaxFragmentImageUniforms, 0);
EXPECT_EQ(backend.GetDynamicParameters().MaxComputeImageUniforms, 9);
@@ -689,6 +693,8 @@ TEST(DirectGLESSanity, PreservesHostPerStageImageUniformLimits) {
caps.MaxImageUnits = 8;
caps.MaxCombinedImageUniforms = 16;
caps.MaxVertexImageUniforms = 2;
caps.MaxTessControlImageUniforms = 6;
caps.MaxTessEvaluationImageUniforms = 7;
caps.MaxGeometryImageUniforms = 3;
caps.MaxFragmentImageUniforms = 4;
caps.MaxComputeImageUniforms = 5;
@@ -696,6 +702,8 @@ TEST(DirectGLESSanity, PreservesHostPerStageImageUniformLimits) {
const auto& params = backend.GetDynamicParameters();
EXPECT_EQ(params.MaxVertexImageUniforms, 2);
EXPECT_EQ(params.MaxTessControlImageUniforms, 6);
EXPECT_EQ(params.MaxTessEvaluationImageUniforms, 7);
EXPECT_EQ(params.MaxGeometryImageUniforms, 3);
EXPECT_EQ(params.MaxFragmentImageUniforms, 4);
EXPECT_EQ(params.MaxComputeImageUniforms, 5);
@@ -1095,6 +1103,8 @@ TEST(GetterSanity, PerStageImageUniformQueriesMatchShaderCompilerLimits) {
params.MaxImageUnits = 8;
params.MaxCombinedImageUniforms = 8;
params.MaxVertexImageUniforms = 1;
params.MaxTessControlImageUniforms = 5;
params.MaxTessEvaluationImageUniforms = 6;
params.MaxGeometryImageUniforms = 2;
params.MaxFragmentImageUniforms = 3;
params.MaxComputeImageUniforms = 4;
@@ -1103,6 +1113,10 @@ TEST(GetterSanity, PerStageImageUniformQueriesMatchShaderCompilerLimits) {
GLint reported = -1;
MG_Impl::GLImpl::GetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &reported);
EXPECT_EQ(reported, 1);
MG_Impl::GLImpl::GetIntegerv(GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS, &reported);
EXPECT_EQ(reported, 5);
MG_Impl::GLImpl::GetIntegerv(GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS, &reported);
EXPECT_EQ(reported, 6);
MG_Impl::GLImpl::GetIntegerv(GL_MAX_GEOMETRY_IMAGE_UNIFORMS, &reported);
EXPECT_EQ(reported, 2);
MG_Impl::GLImpl::GetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &reported);
@@ -1308,8 +1322,17 @@ TEST(GetterSanity, EveryLimitWithABuiltinAgreesWithItsQuery) {
auto previousContext = MG_State::pGLContext.Take();
auto previousBackend = Move(MG_Backend::pActiveBackendObject);
MG_State::pGLContext = MakeUnique<MG_State::GLState::GLContext>();
MG_Backend::pActiveBackendObject =
MakeUnique<DynamicParameterBackend>(MG_Backend::DynamicBackendParameters{}, BackendType::DirectGLES);
// Distinct non-zero image-uniform limits, so the per-stage pairs below cannot agree by both
// falling back to the same default.
MG_Backend::DynamicBackendParameters params;
params.MaxVertexImageUniforms = 1;
params.MaxTessControlImageUniforms = 2;
params.MaxTessEvaluationImageUniforms = 3;
params.MaxGeometryImageUniforms = 4;
params.MaxFragmentImageUniforms = 5;
params.MaxComputeImageUniforms = 6;
params.MaxCombinedImageUniforms = 7;
MG_Backend::pActiveBackendObject = MakeUnique<DynamicParameterBackend>(params, BackendType::DirectGLES);
struct LimitPair {
GLenum pname;
@@ -1330,6 +1353,13 @@ TEST(GetterSanity, EveryLimitWithABuiltinAgreesWithItsQuery) {
{GL_MAX_FRAGMENT_INPUT_COMPONENTS, "gl_MaxFragmentInputComponents"},
{GL_MAX_DRAW_BUFFERS, "gl_MaxDrawBuffers"},
{GL_MAX_IMAGE_UNITS, "gl_MaxImageUnits"},
{GL_MAX_VERTEX_IMAGE_UNIFORMS, "gl_MaxVertexImageUniforms"},
{GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS, "gl_MaxTessControlImageUniforms"},
{GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS, "gl_MaxTessEvaluationImageUniforms"},
{GL_MAX_GEOMETRY_IMAGE_UNIFORMS, "gl_MaxGeometryImageUniforms"},
{GL_MAX_FRAGMENT_IMAGE_UNIFORMS, "gl_MaxFragmentImageUniforms"},
{GL_MAX_COMPUTE_IMAGE_UNIFORMS, "gl_MaxComputeImageUniforms"},
{GL_MAX_COMBINED_IMAGE_UNIFORMS, "gl_MaxCombinedImageUniforms"},
// The SAME token (0x8F39) under two spellings, and the two glslang fields behind them
// must therefore carry the same value.
{GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS, "gl_MaxCombinedImageUnitsAndFragmentOutputs"},
@@ -720,6 +720,9 @@ TEST_F(TranslationCacheTest, TheFrontendFingerprintMovesWithEveryFrontendLimit)
{"params.MaxImageUnits", [](CompileEnv& e) { e.params.MaxImageUnits += 1; }},
{"params.MaxDrawBuffers", [](CompileEnv& e) { e.params.MaxDrawBuffers += 1; }},
{"params.MaxVertexImageUniforms", [](CompileEnv& e) { e.params.MaxVertexImageUniforms += 1; }},
{"params.MaxTessControlImageUniforms", [](CompileEnv& e) { e.params.MaxTessControlImageUniforms += 1; }},
{"params.MaxTessEvaluationImageUniforms",
[](CompileEnv& e) { e.params.MaxTessEvaluationImageUniforms += 1; }},
{"params.MaxGeometryImageUniforms", [](CompileEnv& e) { e.params.MaxGeometryImageUniforms += 1; }},
{"params.MaxFragmentImageUniforms", [](CompileEnv& e) { e.params.MaxFragmentImageUniforms += 1; }},
{"params.MaxComputeImageUniforms", [](CompileEnv& e) { e.params.MaxComputeImageUniforms += 1; }},
@@ -1398,6 +1398,8 @@ namespace MobileGL::MG_Util::BackendLoader {
GLint maxImageUnits = 8;
GLint maxCombinedImageUniforms = 8;
GLint maxVertexImageUniforms = 0;
GLint maxTessControlImageUniforms = 0;
GLint maxTessEvaluationImageUniforms = 0;
GLint maxGeometryImageUniforms = 0;
GLint maxFragmentImageUniforms = 8;
GLint maxComputeImageUniforms = 8;
@@ -1547,12 +1549,14 @@ namespace MobileGL::MG_Util::BackendLoader {
glesFuncs.glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &maxVertexImageUniforms);
glesFuncs.glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &maxFragmentImageUniforms);
glesFuncs.glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &maxComputeImageUniforms);
// Geometry shaders and their image-uniform query are core only in ES 3.2. DirectGLES
// emits ESSL 3.10 on an ES 3.1 context, so reporting zero there is both legal and an
// accurate description of what the backend compiler can consume.
// Geometry and tessellation shaders and their image-uniform queries are core only in
// ES 3.2. DirectGLES emits ESSL 3.10 on an ES 3.1 context, so reporting zero there is
// both legal and an accurate description of what the backend compiler can consume.
if (caps.GLESVersion.Major > 3 ||
(caps.GLESVersion.Major == 3 && caps.GLESVersion.Minor >= 2)) {
glesFuncs.glGetIntegerv(GL_MAX_GEOMETRY_IMAGE_UNIFORMS, &maxGeometryImageUniforms);
glesFuncs.glGetIntegerv(GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS, &maxTessControlImageUniforms);
glesFuncs.glGetIntegerv(GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS, &maxTessEvaluationImageUniforms);
}
// Closes the bracket opened before the run: every local above now holds either the
// driver's answer or a floor, and nothing this function asked for is left in the error
@@ -1864,6 +1868,8 @@ namespace MobileGL::MG_Util::BackendLoader {
caps.MaxImageUnits = maxImageUnits;
caps.MaxCombinedImageUniforms = maxCombinedImageUniforms;
caps.MaxVertexImageUniforms = maxVertexImageUniforms;
caps.MaxTessControlImageUniforms = maxTessControlImageUniforms;
caps.MaxTessEvaluationImageUniforms = maxTessEvaluationImageUniforms;
caps.MaxGeometryImageUniforms = maxGeometryImageUniforms;
caps.MaxFragmentImageUniforms = maxFragmentImageUniforms;
caps.MaxComputeImageUniforms = maxComputeImageUniforms;
@@ -1962,6 +1968,8 @@ namespace MobileGL::MG_Util::BackendLoader {
MGLOG_I(" GL_MAX_IMAGE_UNITS: %d", caps.MaxImageUnits);
MGLOG_I(" GL_MAX_COMBINED_IMAGE_UNIFORMS: %d", caps.MaxCombinedImageUniforms);
MGLOG_I(" GL_MAX_VERTEX_IMAGE_UNIFORMS: %d", caps.MaxVertexImageUniforms);
MGLOG_I(" GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS: %d", caps.MaxTessControlImageUniforms);
MGLOG_I(" GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS: %d", caps.MaxTessEvaluationImageUniforms);
MGLOG_I(" GL_MAX_GEOMETRY_IMAGE_UNIFORMS: %d", caps.MaxGeometryImageUniforms);
MGLOG_I(" GL_MAX_FRAGMENT_IMAGE_UNIFORMS: %d", caps.MaxFragmentImageUniforms);
MGLOG_I(" GL_MAX_COMPUTE_IMAGE_UNIFORMS: %d", caps.MaxComputeImageUniforms);
@@ -1364,6 +1364,8 @@ namespace MobileGL {
Int MaxImageUnits = 8;
Int MaxCombinedImageUniforms = 8;
Int MaxVertexImageUniforms = 0;
Int MaxTessControlImageUniforms = 0;
Int MaxTessEvaluationImageUniforms = 0;
Int MaxGeometryImageUniforms = 0;
Int MaxFragmentImageUniforms = 8;
Int MaxComputeImageUniforms = 8;
@@ -61,6 +61,8 @@ namespace MobileGL::MG_Util::ShaderTranspiler {
HashValue(state, env.params.MaxImageUnits);
HashValue(state, env.params.MaxDrawBuffers);
HashValue(state, env.params.MaxVertexImageUniforms);
HashValue(state, env.params.MaxTessControlImageUniforms);
HashValue(state, env.params.MaxTessEvaluationImageUniforms);
HashValue(state, env.params.MaxGeometryImageUniforms);
HashValue(state, env.params.MaxFragmentImageUniforms);
HashValue(state, env.params.MaxComputeImageUniforms);
@@ -212,6 +212,8 @@ namespace MobileGL {
Resources.maxCombinedShaderOutputResources =
Resources.maxCombinedImageUnitsAndFragmentOutputs;
Resources.maxVertexImageUniforms = dynamicParameters.MaxVertexImageUniforms;
Resources.maxTessControlImageUniforms = dynamicParameters.MaxTessControlImageUniforms;
Resources.maxTessEvaluationImageUniforms = dynamicParameters.MaxTessEvaluationImageUniforms;
Resources.maxGeometryImageUniforms = dynamicParameters.MaxGeometryImageUniforms;
Resources.maxFragmentImageUniforms = dynamicParameters.MaxFragmentImageUniforms;
Resources.maxComputeImageUniforms = dynamicParameters.MaxComputeImageUniforms;