mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-18 00:58:30 +09:00
[Fix] (GLImpl, DirectGLES, DirectVulkan): floor every advertised sample cap and clamp the realised count in the backends
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#include <MG_Backend/BackendObjects.h>
|
||||
#include <MG_Util/Metrics/TextureMetrics.h>
|
||||
#include <MG_Impl/GLImpl/Texture/Validators.h>
|
||||
#include <MG_Impl/GLImpl/Getter/GL_Getter.h>
|
||||
#include <MG_State/GLState/ErrorState/Error.h>
|
||||
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
|
||||
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
|
||||
@@ -617,16 +618,17 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (MG_Backend::pActiveBackendObject == nullptr) {
|
||||
return std::numeric_limits<Int>::max();
|
||||
}
|
||||
return std::max(MG_Backend::pActiveBackendObject->GetDynamicParameters().MaxSamples, 1);
|
||||
return GetAdvertisedMaxSamples();
|
||||
}
|
||||
|
||||
// GL_MAX_SAMPLES is the ceiling over all formats; an integer format has its own, lower
|
||||
// one (GL_MAX_INTEGER_SAMPLES) and GL 4.6 core 9.2.4 makes exceeding it INVALID_OPERATION.
|
||||
// The multisample TEXTURE path already resolves the limit per format
|
||||
// (GL_Texture.cpp, GetMaxTextureSamplesForFormat); renderbuffers only ever compared
|
||||
// against GL_MAX_SAMPLES, so on a driver where the two differ - Adreno reports
|
||||
// GL_MAX_SAMPLES 4 and GL_MAX_INTEGER_SAMPLES 1 - an integer renderbuffer accepted a
|
||||
// sample count the format cannot deliver, and said GL_NO_ERROR about it.
|
||||
// GL_MAX_SAMPLES is the ceiling over all formats; an integer format has its own
|
||||
// (GL_MAX_INTEGER_SAMPLES) and GL 4.6 core 9.2.4 makes exceeding it INVALID_OPERATION.
|
||||
// The multisample TEXTURE path resolves the limit per format the same way
|
||||
// (GL_Texture.cpp, GetMaxSupportedTextureSamples). Both are floored to the value MobileGL
|
||||
// advertises: on a driver where the two differ - Adreno reports GL_MAX_SAMPLES 4 and
|
||||
// GL_MAX_INTEGER_SAMPLES 1 - rejecting the advertised count here only moves the failure
|
||||
// from the driver into MobileGL, so the frontend accepts it and the backend clamps the
|
||||
// count it actually hands the driver.
|
||||
Int GetMaxRenderbufferSamplesForFormat_State(TextureInternalFormat format) {
|
||||
if (MG_Backend::pActiveBackendObject == nullptr) {
|
||||
return std::numeric_limits<Int>::max();
|
||||
@@ -645,7 +647,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (!isIntegerFormat) {
|
||||
return GetMaxRenderbufferSamples_State();
|
||||
}
|
||||
return std::max(dynamicParameters.MaxIntegerSamples, 1);
|
||||
// Per-format still, but never below the ceiling glGetIntegerv(GL_MAX_SAMPLES) promised:
|
||||
// the driver's raw GL_MAX_INTEGER_SAMPLES stays the *backend* limit and the backend
|
||||
// clamps to it, while the frontend honours what it advertised.
|
||||
return std::max(dynamicParameters.MaxIntegerSamples, GetAdvertisedMaxSamples());
|
||||
}
|
||||
|
||||
Bool ValidateRenderbufferStorageSize_State(GLsizei width, GLsizei height, const char* caller) {
|
||||
|
||||
@@ -422,6 +422,18 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// GL 4.6 core table 23.53 requires GL_MAX_SAMPLES >= 4, so the driver's value is floored
|
||||
// before it is advertised. Every other multisample ceiling MobileGL advertises has to be
|
||||
// floored the same way: promising 4 samples globally while answering GL_MAX_INTEGER_SAMPLES
|
||||
// 1 - which is exactly what Adreno reports - makes the frontend reject the very count it
|
||||
// just told the application to use. The backends clamp the realised count instead.
|
||||
GLint GetAdvertisedMaxSamples() {
|
||||
if (MG_Backend::pActiveBackendObject == nullptr) {
|
||||
return kFrontendMaxSamples;
|
||||
}
|
||||
return std::max(MG_Backend::pActiveBackendObject->GetDynamicParameters().MaxSamples, kFrontendMaxSamples);
|
||||
}
|
||||
|
||||
/* @INSERTION_POINT:FUNCTION_IMPLEMENTATION@ */
|
||||
const GLubyte* GetString(GLenum name) {
|
||||
static String vendorString;
|
||||
@@ -2117,7 +2129,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
*params = dynamicParameters.MaxClipDistances;
|
||||
break;
|
||||
case GL_MAX_COLOR_TEXTURE_SAMPLES:
|
||||
*params = dynamicParameters.MaxColorTextureSamples;
|
||||
*params = std::max(dynamicParameters.MaxColorTextureSamples, GetAdvertisedMaxSamples());
|
||||
break;
|
||||
case GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS:
|
||||
*params = GetMaxCombinedUniformComponents(kFrontendMaxFragmentUniformComponents,
|
||||
@@ -2147,7 +2159,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
*params = dynamicParameters.MaxCubeMapTextureSize;
|
||||
break;
|
||||
case GL_MAX_DEPTH_TEXTURE_SAMPLES:
|
||||
*params = dynamicParameters.MaxDepthTextureSamples;
|
||||
*params = std::max(dynamicParameters.MaxDepthTextureSamples, GetAdvertisedMaxSamples());
|
||||
break;
|
||||
case GL_MAX_FRAMEBUFFER_WIDTH:
|
||||
*params = dynamicParameters.MaxFramebufferWidth;
|
||||
@@ -2174,7 +2186,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
*params = dynamicParameters.MaxComputeImageUniforms;
|
||||
break;
|
||||
case GL_MAX_INTEGER_SAMPLES:
|
||||
*params = dynamicParameters.MaxIntegerSamples;
|
||||
*params = std::max(dynamicParameters.MaxIntegerSamples, GetAdvertisedMaxSamples());
|
||||
break;
|
||||
case GL_MAX_RENDERBUFFER_SIZE:
|
||||
*params = dynamicParameters.MaxRenderbufferSize;
|
||||
@@ -2340,7 +2352,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
: dynamicParameters.MaxDrawBuffers;
|
||||
break;
|
||||
case GL_MAX_SAMPLES:
|
||||
*params = std::max(dynamicParameters.MaxSamples, kFrontendMaxSamples);
|
||||
*params = GetAdvertisedMaxSamples();
|
||||
break;
|
||||
case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT:
|
||||
// Float state (see GetFloatv); rounded to nearest for the integer query per GL 3.3 6.1.2.
|
||||
|
||||
@@ -24,4 +24,8 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
void GetInteger64i_v(GLenum target, GLuint index, GLint64* data);
|
||||
GLenum GetError();
|
||||
GLenum GetGraphicsResetStatus();
|
||||
// The GL_MAX_SAMPLES value MobileGL advertises, i.e. the driver's value floored to the GL
|
||||
// core minimum. Frontend multisample validators have to honour this ceiling for every
|
||||
// format, otherwise MobileGL rejects a sample count it advertised itself.
|
||||
GLint GetAdvertisedMaxSamples();
|
||||
} // namespace MobileGL::MG_Impl::GLImpl
|
||||
|
||||
@@ -474,15 +474,48 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
target == TextureTarget::Texture2DMultisampleArray;
|
||||
}
|
||||
|
||||
Int GetMaxSupportedTextureSamples(TextureInternalFormat textureInternalFormat) {
|
||||
// The largest count the backend actually probed for this format on this target, or 0 when
|
||||
// it has no answer for the pair. Both backends build the list in descending order.
|
||||
Int GetProbedMaxTextureSamples(TextureTarget textureTarget, TextureInternalFormat textureInternalFormat) {
|
||||
if (MG_Backend::pActiveBackendObject == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
const SizeT targetIndex = MG_Backend::GetFormatCapabilityTargetIndex(textureTarget);
|
||||
const SizeT formatIndex = static_cast<SizeT>(textureInternalFormat);
|
||||
if (targetIndex >= MG_Backend::kFormatCapabilityTargetCount ||
|
||||
formatIndex >= MG_Backend::kFormatCapabilityFormatCount) {
|
||||
return 0;
|
||||
}
|
||||
const auto& sampleCounts =
|
||||
MG_Backend::pActiveBackendObject->GetFormatCapabilities().SampleCounts[targetIndex][formatIndex];
|
||||
return sampleCounts.empty() ? 0 : sampleCounts.front();
|
||||
}
|
||||
|
||||
// The ceiling the frontend enforces, which must never be lower than the one MobileGL
|
||||
// advertises: the CTS - and real applications - read GL_MAX_SAMPLES once and hand that
|
||||
// exact count to glTexImage*Multisample for every format. Answering 4 there and then
|
||||
// rejecting 4 here because the ES driver reports GL_MAX_INTEGER_SAMPLES 1 (Adreno) is a
|
||||
// self-inconsistency, not a spec-mandated error. The backends clamp the count they hand
|
||||
// the driver; the shadow state keeps reporting what the application asked for.
|
||||
Int GetMaxSupportedTextureSamples(TextureTarget textureTarget,
|
||||
TextureInternalFormat textureInternalFormat) {
|
||||
if (MG_Backend::pActiveBackendObject == nullptr) {
|
||||
return std::numeric_limits<Int>::max();
|
||||
}
|
||||
|
||||
const Int advertisedMaxSamples = GetAdvertisedMaxSamples();
|
||||
// glGetInternalformativ(GL_SAMPLES) is answered from this very list (GetInternalformativ
|
||||
// below), and GL 4.6 core 8.8 makes that query the definition of the per-format
|
||||
// maximum - validating against anything else is how the two answers drifted apart.
|
||||
const Int probedMaxSamples = GetProbedMaxTextureSamples(textureTarget, textureInternalFormat);
|
||||
if (probedMaxSamples > 0) {
|
||||
return std::max(probedMaxSamples, advertisedMaxSamples);
|
||||
}
|
||||
|
||||
const auto& dynamicParameters = MG_Backend::pActiveBackendObject->GetDynamicParameters();
|
||||
if (MG_Util::IsDepthFormatInternalFormat(textureInternalFormat) ||
|
||||
MG_Util::IsStencilFormatInternalFormat(textureInternalFormat)) {
|
||||
return std::max(dynamicParameters.MaxDepthTextureSamples, 1);
|
||||
return std::max(dynamicParameters.MaxDepthTextureSamples, advertisedMaxSamples);
|
||||
}
|
||||
|
||||
GLenum normalizedInternalFormat = MG_Util::ConvertTextureInternalFormatToGLEnum(textureInternalFormat);
|
||||
@@ -495,7 +528,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
normalizedFormat == GL_RGB_INTEGER || normalizedFormat == GL_RGBA_INTEGER;
|
||||
return std::max(isIntegerFormat ? dynamicParameters.MaxIntegerSamples
|
||||
: dynamicParameters.MaxColorTextureSamples,
|
||||
1);
|
||||
advertisedMaxSamples);
|
||||
}
|
||||
|
||||
Bool ValidateTextureMultisampleStorage(TextureTarget textureTarget, GLsizei samples, GLsizei width,
|
||||
@@ -532,7 +565,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
// dimensions, and GL CTS's per-case state reset (gluStateReset) clears the default
|
||||
// GL_TEXTURE_2D_MULTISAMPLE_ARRAY texture with glTexImage3DMultisample(..., 0, 0, 0).
|
||||
|
||||
const Int maxSamples = GetMaxSupportedTextureSamples(textureInternalFormat);
|
||||
const Int maxSamples = GetMaxSupportedTextureSamples(textureTarget, textureInternalFormat);
|
||||
if (samples > maxSamples) {
|
||||
// GL specifies INVALID_OPERATION - not INVALID_VALUE - when the sample count
|
||||
// exceeds what the format supports, and the native Adreno driver agrees.
|
||||
|
||||
Reference in New Issue
Block a user