mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-14 07:08:32 +09:00
[Fix] (GLImpl, DirectGLES, DirectVulkan): floor every advertised sample cap and clamp the realised count in the backends
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "BackendObject_DirectGLES.h"
|
||||
#include "MG_Backend/BackendObject.h"
|
||||
#include "MG_Backend/BackendObjects.h"
|
||||
#include <MG_Backend/DirectGLES/DirectGLES.h>
|
||||
#include <MG_Backend/DirectGLES/Managers.h>
|
||||
#include <MG_Backend/DirectGLES/Utils.h>
|
||||
@@ -782,6 +783,29 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
PopulateFormatCapabilitiesImpl(gl, capabilities, cache);
|
||||
}
|
||||
|
||||
Int ClampSamplesToBackendSupport(SizeT targetIndex, TextureInternalFormat logicalFormat, GLenum imageFormat,
|
||||
Int samples) {
|
||||
if (samples <= 1) {
|
||||
return samples;
|
||||
}
|
||||
|
||||
Int maxSamples = 0;
|
||||
const SizeT formatIndex = static_cast<SizeT>(logicalFormat);
|
||||
if (pActiveBackendObject && targetIndex < kFormatCapabilityTargetCount &&
|
||||
formatIndex < kFormatCapabilityFormatCount) {
|
||||
// Descending, so the head is the largest count this device actually allocated.
|
||||
const Vector<Int>& probedCounts =
|
||||
pActiveBackendObject->GetFormatCapabilities().SampleCounts[targetIndex][formatIndex];
|
||||
if (!probedCounts.empty()) {
|
||||
maxSamples = probedCounts.front();
|
||||
}
|
||||
}
|
||||
if (maxSamples <= 0) {
|
||||
maxSamples = GetGLESFormatMaxSamples(g_GLESCapabilities, logicalFormat, imageFormat);
|
||||
}
|
||||
return std::min(samples, std::max(maxSamples, 1));
|
||||
}
|
||||
|
||||
BackendObject_DirectGLES::~BackendObject_DirectGLES() {
|
||||
DestroyEGLContext();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,16 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
const MG_External::GLESCapabilities& capabilities,
|
||||
FormatCapabilityCache& cache);
|
||||
|
||||
// Clamps a requested sample count down to what the ES driver can really deliver for this
|
||||
// format on this format-capability target: the probed per-format list when there is one, the
|
||||
// driver's per-class GL_MAX_*_SAMPLES otherwise. The frontend deliberately validates against
|
||||
// the count MobileGL advertises instead (GL_Getter's GetAdvertisedMaxSamples), which on a
|
||||
// driver reporting GL_MAX_INTEGER_SAMPLES 1 is higher than the driver accepts, so every ES
|
||||
// allocation call has to come through here. The shadow state keeps the requested count, so
|
||||
// GL_TEXTURE_SAMPLES and framebuffer completeness still answer what the application asked for.
|
||||
Int ClampSamplesToBackendSupport(SizeT targetIndex, TextureInternalFormat logicalFormat, GLenum imageFormat,
|
||||
Int samples);
|
||||
|
||||
class BackendObject_DirectGLES : public BackendObject {
|
||||
public:
|
||||
~BackendObject_DirectGLES() override;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Managers.h"
|
||||
#include "Utils.h"
|
||||
#include "DirectGLES.h"
|
||||
#include "BackendObject_DirectGLES.h"
|
||||
#include <Config.h>
|
||||
#include <MG_Util/ShaderTranspiler/ShaderCompiler.h>
|
||||
|
||||
@@ -2648,16 +2649,24 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
if (TextureImpl::IsMultisampleTextureTarget(targetInternal)) {
|
||||
DebugImpl::ErrorLopper::Clear();
|
||||
BufferImpl::BindPixelUnpackBufferId(0); // no-op once the resting 0 state is pinned
|
||||
// The frontend validates against the count MobileGL advertises, which can
|
||||
// exceed what the driver takes for this format (Adreno: GL_MAX_SAMPLES 4,
|
||||
// GL_MAX_INTEGER_SAMPLES 1). Clamp the ES call - and only the ES call:
|
||||
// stateTextureObject keeps the requested count so GL_TEXTURE_SAMPLES and
|
||||
// framebuffer completeness still report what the application asked for.
|
||||
const auto backendSamples = static_cast<GLsizei>(ClampSamplesToBackendSupport(
|
||||
GetFormatCapabilityTargetIndex(targetInternal), textureMipmapObject->GetFormat(),
|
||||
glFormat, static_cast<Int>(stateTextureObject->GetSamples())));
|
||||
switch (targetInternal) {
|
||||
case TextureTarget::Texture2DMultisample:
|
||||
g_GLESFuncs.glTexStorage2DMultisample(
|
||||
target, static_cast<GLsizei>(stateTextureObject->GetSamples()), glInternalFormat,
|
||||
target, backendSamples, glInternalFormat,
|
||||
static_cast<GLsizei>(baseSize.x()), static_cast<GLsizei>(baseSize.y()),
|
||||
stateTextureObject->HasFixedSampleLocations() ? GL_TRUE : GL_FALSE);
|
||||
break;
|
||||
case TextureTarget::Texture2DMultisampleArray:
|
||||
g_GLESFuncs.glTexStorage3DMultisample(
|
||||
target, static_cast<GLsizei>(stateTextureObject->GetSamples()), glInternalFormat,
|
||||
target, backendSamples, glInternalFormat,
|
||||
static_cast<GLsizei>(baseSize.x()), static_cast<GLsizei>(baseSize.y()),
|
||||
static_cast<GLsizei>(baseSize.z()),
|
||||
stateTextureObject->HasFixedSampleLocations() ? GL_TRUE : GL_FALSE);
|
||||
@@ -5621,9 +5630,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
TextureImpl::GenerateRenderbufferFormatInfo(internalFormat, &glInternalFormat, &glFormat, &glType);
|
||||
|
||||
if (samples > 0) {
|
||||
g_GLESFuncs.glRenderbufferStorageMultisample(
|
||||
GL_RENDERBUFFER, static_cast<GLsizei>(samples), glInternalFormat, static_cast<GLsizei>(width),
|
||||
static_cast<GLsizei>(height));
|
||||
// Same clamp as the multisample texture path: the frontend accepts the count it
|
||||
// advertised, the driver only takes the count it supports for this format, and
|
||||
// the state object keeps reporting the requested one.
|
||||
const auto backendSamples = static_cast<GLsizei>(ClampSamplesToBackendSupport(
|
||||
GetRenderbufferFormatCapabilityTargetIndex(), internalFormat, glFormat, samples));
|
||||
g_GLESFuncs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, backendSamples, glInternalFormat,
|
||||
static_cast<GLsizei>(width),
|
||||
static_cast<GLsizei>(height));
|
||||
} else {
|
||||
g_GLESFuncs.glRenderbufferStorage(GL_RENDERBUFFER, glInternalFormat, static_cast<GLsizei>(width),
|
||||
static_cast<GLsizei>(height));
|
||||
|
||||
@@ -1848,6 +1848,19 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rounded == 0 && (supported & VK_SAMPLE_COUNT_1_BIT) != 0) {
|
||||
// Nothing at two samples or above. Reachable because the frontend validates
|
||||
// multisample allocations against the count MobileGL ADVERTISES (GL requires
|
||||
// GL_MAX_SAMPLES >= 4) rather than against the device's per-format support, so
|
||||
// a format this device cannot multisample at all now gets here instead of
|
||||
// being refused up front. Keeping the unsupported count would hand
|
||||
// vkCreateImage an invalid VkImageCreateInfo; one sample is at least a legal
|
||||
// image, and the samples-08726 hazard above is the lesser of the two.
|
||||
MGLOG_W_ONCE("Multisample texture format %d supports no count above one on this device; "
|
||||
"backing it with a single sample",
|
||||
static_cast<Int>(format));
|
||||
rounded = static_cast<Uint32>(VK_SAMPLE_COUNT_1_BIT);
|
||||
}
|
||||
if (rounded != 0) {
|
||||
resolvedSampleCount = static_cast<VkSampleCountFlagBits>(rounded);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user