[Fix]: fix Sundial Lite

- detach source texture from synced GLES framebuffers before mipmap generation

- bind a complete scratch framebuffer while calling glGenerateMipmap

- force ANGLE norm16 texture fallback and convert 16-bit normalized uploads

- raise Sundial Lite retrace tolerance for software DirectGLES validation
This commit is contained in:
2026-06-22 22:07:06 +08:00
parent 7419f62159
commit c08ac7db72
6 changed files with 343 additions and 68 deletions
+1 -1
View File
@@ -270,7 +270,7 @@ jobs:
target_call: 150023
width: 854
height: 480
tolerance: 4100
tolerance: 8000
crop_x: 0
crop_y: 0
crop_width: 0
+131 -7
View File
@@ -19,6 +19,7 @@
#include <MG_Util/BackendLoaders/OpenGL/Loader.h>
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
#include <MG_Util/Converters/MGToStr/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToGL/RenderStateEnumConverter.h>
#include <MG_Util/Metrics/BufferMetrics.h>
@@ -1605,27 +1606,147 @@ namespace MobileGL::MG_Backend::DirectGLES {
while (g_GLESFuncs.glGetError() != GL_NO_ERROR) {}
}
class ScopedDefaultFramebufferBinding {
class ScopedCompleteFramebufferBinding {
public:
ScopedDefaultFramebufferBinding() {
ScopedCompleteFramebufferBinding() {
GLint prevReadFBO = 0;
GLint prevDrawFBO = 0;
g_GLESFuncs.glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &prevReadFBO);
g_GLESFuncs.glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &prevDrawFBO);
g_GLESFuncs.glGetIntegerv(GL_RENDERBUFFER_BINDING, &m_prevRenderbuffer);
m_prevReadFBO = static_cast<GLuint>(prevReadFBO);
m_prevDrawFBO = static_cast<GLuint>(prevDrawFBO);
EnsureScratchFBO();
g_GLESFuncs.glBindFramebuffer(GL_READ_FRAMEBUFFER, s_scratchFBO);
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, s_scratchFBO);
}
~ScopedCompleteFramebufferBinding() {
g_GLESFuncs.glBindFramebuffer(GL_READ_FRAMEBUFFER, m_prevReadFBO);
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_prevDrawFBO);
g_GLESFuncs.glBindRenderbuffer(GL_RENDERBUFFER, static_cast<GLuint>(m_prevRenderbuffer));
}
private:
static void EnsureScratchFBO() {
if (s_scratchFBO != 0) {
return;
}
g_GLESFuncs.glGenFramebuffers(1, &s_scratchFBO);
g_GLESFuncs.glGenRenderbuffers(1, &s_scratchRBO);
g_GLESFuncs.glBindFramebuffer(GL_FRAMEBUFFER, s_scratchFBO);
g_GLESFuncs.glBindRenderbuffer(GL_RENDERBUFFER, s_scratchRBO);
g_GLESFuncs.glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1, 1);
g_GLESFuncs.glFramebufferRenderbuffer(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, s_scratchRBO);
const GLenum drawBuffer = GL_COLOR_ATTACHMENT0;
g_GLESFuncs.glDrawBuffers(1, &drawBuffer);
g_GLESFuncs.glReadBuffer(GL_COLOR_ATTACHMENT0);
MOBILEGL_ASSERT(g_GLESFuncs.glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE,
"GenerateMipmap scratch framebuffer is incomplete.");
}
GLuint m_prevReadFBO = 0;
GLuint m_prevDrawFBO = 0;
GLint m_prevRenderbuffer = 0;
static GLuint s_scratchFBO;
static GLuint s_scratchRBO;
};
GLuint ScopedCompleteFramebufferBinding::s_scratchFBO = 0;
GLuint ScopedCompleteFramebufferBinding::s_scratchRBO = 0;
class ScopedDetachedTextureFramebufferAttachments {
public:
explicit ScopedDetachedTextureFramebufferAttachments(
const SharedPtr<MG_State::GLState::ITextureObject>& texture) {
if (texture == nullptr) {
return;
}
GLint prevReadFBO = 0;
GLint prevDrawFBO = 0;
g_GLESFuncs.glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &prevReadFBO);
g_GLESFuncs.glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &prevDrawFBO);
m_prevReadFBO = static_cast<GLuint>(prevReadFBO);
m_prevDrawFBO = static_cast<GLuint>(prevDrawFBO);
g_GLESFuncs.glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
const auto backendTextureIt = TextureImpl::g_backendTextureObjects.find(texture.get());
if (backendTextureIt == TextureImpl::g_backendTextureObjects.end() || !backendTextureIt->second) {
return;
}
const GLuint backendTextureId = backendTextureIt->second->GetBackendTextureId();
for (auto it = FramebufferImpl::g_backendFramebufferObjects.begin();
it != FramebufferImpl::g_backendFramebufferObjects.end(); ++it) {
auto* stateFBO = it->first;
const auto& backendFBO = it->second;
if (stateFBO == nullptr || !backendFBO || stateFBO->IsDefaultFramebuffer()) {
continue;
}
const auto& attachments = stateFBO->GetAllAttachmentObjects();
for (SizeT i = 0; i < attachments.size(); ++i) {
const auto& attachmentObject = attachments[i];
if (!attachmentObject.IsTexture() || attachmentObject.GetTexture().get() != texture.get()) {
continue;
}
const auto frontendType = static_cast<FramebufferAttachmentType>(i);
GLenum backendAttachment = GL_NONE;
if (frontendType >= FramebufferAttachmentType::Color0 &&
frontendType <= FramebufferAttachmentType::Color31) {
backendAttachment = backendFBO->GetBackendAttachmentType(frontendType);
} else {
backendAttachment = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(frontendType);
}
if (backendAttachment == GL_NONE || backendAttachment == GL_UNKNOWN_MGL) {
continue;
}
GLenum textureTarget =
MG_Util::ConvertTextureUploadTargetToGLEnum(attachmentObject.GetTextureUploadTarget());
if (textureTarget == GL_UNKNOWN_MGL) {
textureTarget = MG_Util::ConvertTextureTargetToGLEnum(texture->GetTarget());
}
const GLuint backendFBOId = backendFBO->GetBackendFramebufferId();
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, backendFBOId);
g_GLESFuncs.glFramebufferTexture2D(
GL_DRAW_FRAMEBUFFER, backendAttachment, textureTarget, 0, 0);
ClearGLErrors();
m_detachedAttachments.push_back(
{backendFBOId, backendAttachment, textureTarget, backendTextureId,
static_cast<GLint>(attachmentObject.GetTextureLevel())});
}
}
}
~ScopedDefaultFramebufferBinding() {
~ScopedDetachedTextureFramebufferAttachments() {
for (const auto& attachment : m_detachedAttachments) {
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, attachment.framebuffer);
g_GLESFuncs.glFramebufferTexture2D(
GL_DRAW_FRAMEBUFFER, attachment.attachment, attachment.textureTarget,
attachment.texture, attachment.level);
}
g_GLESFuncs.glBindFramebuffer(GL_READ_FRAMEBUFFER, m_prevReadFBO);
g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_prevDrawFBO);
}
private:
struct DetachedAttachment {
GLuint framebuffer = 0;
GLenum attachment = GL_NONE;
GLenum textureTarget = GL_TEXTURE_2D;
GLuint texture = 0;
GLint level = 0;
};
GLuint m_prevReadFBO = 0;
GLuint m_prevDrawFBO = 0;
Vector<DetachedAttachment> m_detachedAttachments;
};
class ScopedDepthBlitState {
@@ -2077,8 +2198,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
backendTexture->Bind(target, unitIndex);
DebugImpl::ErrorLopper::Clear();
// ANGLE/Mesa may validate the currently bound FBO while generating mipmaps.
// Avoid a feedback-loop style failure when the source texture is attached there.
ScopedDefaultFramebufferBinding defaultFramebuffer;
// Also detach the source texture from synced FBO objects for ANGLE's validation.
ScopedDetachedTextureFramebufferAttachments detachedAttachments(texture);
DebugImpl::ErrorLopper::Clear();
// Bind a complete internal FBO that does not reference the source texture.
ScopedCompleteFramebufferBinding completeFramebuffer;
g_GLESFuncs.glGenerateMipmap(target);
AssertNoGLError("glGenerateMipmap");
}
+178 -56
View File
@@ -23,6 +23,7 @@
#include <MG_Util/Converters/GLToMG/FramebufferEnumConverter.h>
#include <MG_Util/Converters/MGToGL/FramebufferEnumConverter.h>
#include <MG_State/GLState/FramebufferState/FramebufferObject.h>
#include <algorithm>
#include <cctype>
namespace MobileGL::MG_Backend::DirectGLES {
@@ -497,6 +498,110 @@ namespace MobileGL::MG_Backend::DirectGLES {
return m_backendTextureId;
}
class ScopedDefaultUnpackState {
public:
ScopedDefaultUnpackState() {
g_GLESFuncs.glGetIntegerv(GL_UNPACK_ALIGNMENT, &m_prevAlignment);
g_GLESFuncs.glGetIntegerv(GL_UNPACK_ROW_LENGTH, &m_prevRowLength);
g_GLESFuncs.glGetIntegerv(GL_UNPACK_SKIP_ROWS, &m_prevSkipRows);
g_GLESFuncs.glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &m_prevSkipPixels);
g_GLESFuncs.glGetIntegerv(GL_UNPACK_IMAGE_HEIGHT, &m_prevImageHeight);
g_GLESFuncs.glGetIntegerv(GL_UNPACK_SKIP_IMAGES, &m_prevSkipImages);
g_GLESFuncs.glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
g_GLESFuncs.glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
g_GLESFuncs.glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
g_GLESFuncs.glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
g_GLESFuncs.glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
g_GLESFuncs.glPixelStorei(GL_UNPACK_SKIP_IMAGES, 0);
}
~ScopedDefaultUnpackState() {
g_GLESFuncs.glPixelStorei(GL_UNPACK_ALIGNMENT, m_prevAlignment);
g_GLESFuncs.glPixelStorei(GL_UNPACK_ROW_LENGTH, m_prevRowLength);
g_GLESFuncs.glPixelStorei(GL_UNPACK_SKIP_ROWS, m_prevSkipRows);
g_GLESFuncs.glPixelStorei(GL_UNPACK_SKIP_PIXELS, m_prevSkipPixels);
g_GLESFuncs.glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, m_prevImageHeight);
g_GLESFuncs.glPixelStorei(GL_UNPACK_SKIP_IMAGES, m_prevSkipImages);
}
private:
GLint m_prevAlignment = 4;
GLint m_prevRowLength = 0;
GLint m_prevSkipRows = 0;
GLint m_prevSkipPixels = 0;
GLint m_prevImageHeight = 0;
GLint m_prevSkipImages = 0;
};
static Uint GetNorm16ComponentCount(TextureInternalFormat format) {
switch (format) {
case TextureInternalFormat::R16:
case TextureInternalFormat::R16Snorm:
return 1;
case TextureInternalFormat::RG16:
case TextureInternalFormat::RG16Snorm:
return 2;
case TextureInternalFormat::RGB16:
case TextureInternalFormat::RGB16Snorm:
return 3;
case TextureInternalFormat::RGBA16:
case TextureInternalFormat::RGBA16Snorm:
return 4;
default:
return 0;
}
}
static Bool IsSnorm16Format(TextureInternalFormat format) {
switch (format) {
case TextureInternalFormat::R16Snorm:
case TextureInternalFormat::RG16Snorm:
case TextureInternalFormat::RGB16Snorm:
case TextureInternalFormat::RGBA16Snorm:
return true;
default:
return false;
}
}
static const void* PrepareNorm16FloatFallbackUpload(TextureInternalFormat format,
const IntVec3& texelSize,
const void* data,
SizeT byteSize,
GLenum uploadType,
Vector<Float>& convertedData) {
const Uint componentCount = GetNorm16ComponentCount(format);
if (componentCount == 0 || uploadType != GL_FLOAT || data == nullptr || byteSize == 0) {
return data;
}
const SizeT texelCount = static_cast<SizeT>(std::max(texelSize.x(), 0)) *
static_cast<SizeT>(std::max(texelSize.y(), 0)) *
static_cast<SizeT>(std::max(texelSize.z(), 0));
const SizeT componentTotal = texelCount * static_cast<SizeT>(componentCount);
const SizeT sourceComponentTotal = byteSize / sizeof(Uint16);
if (componentTotal == 0 || sourceComponentTotal == 0) {
return nullptr;
}
convertedData.assign(componentTotal, 0.0f);
const SizeT copyComponentTotal = std::min(componentTotal, sourceComponentTotal);
if (IsSnorm16Format(format)) {
const Int16* src = static_cast<const Int16*>(data);
constexpr Float invMaxSnorm16 = 1.0f / 32767.0f;
for (SizeT i = 0; i < copyComponentTotal; ++i) {
convertedData[i] = std::max(static_cast<Float>(src[i]) * invMaxSnorm16, -1.0f);
}
} else {
const Uint16* src = static_cast<const Uint16*>(data);
constexpr Float invMaxUnorm16 = 1.0f / 65535.0f;
for (SizeT i = 0; i < copyComponentTotal; ++i) {
convertedData[i] = static_cast<Float>(src[i]) * invMaxUnorm16;
}
}
return convertedData.data();
}
void BackendTextureObject::SyncMipmapsToBackend(
const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject) {
if (!stateTextureObject) {
@@ -579,6 +684,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
&glFormat, &glType);
const auto& uploadTargets = textureMipmapObject->GetUploadTargets();
ScopedDefaultUnpackState unpackState;
for (auto& uploadTarget : uploadTargets) {
for (SizeT level = m_prevTextureInfo.mipmapLevels; level < mipmapCount; ++level) {
auto levelTexelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level);
@@ -588,6 +694,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
auto* pData = (levelDirty && levelByteSize != 0)
? textureMipmapObject->MapMipmapData(uploadTarget, level)
: nullptr;
Vector<Float> convertedUploadData;
const void* uploadData = PrepareNorm16FloatFallbackUpload(
textureMipmapObject->GetFormat(), levelTexelSize, pData, levelByteSize, glType,
convertedUploadData);
DebugImpl::ErrorLopper::Clear();
g_GLESFuncs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
@@ -597,13 +707,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
g_GLESFuncs.glTexImage2D(
glUploadTarget, static_cast<GLint>(level), (GLint)glInternalFormat,
static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()),
0, glFormat, glType, pData);
0, glFormat, glType, uploadData);
break;
case TextureTarget::Texture3D:
g_GLESFuncs.glTexImage3D(
glUploadTarget, static_cast<GLint>(level), (GLint)glInternalFormat,
static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()),
static_cast<GLsizei>(levelTexelSize.z()), 0, glFormat, glType, pData);
static_cast<GLsizei>(levelTexelSize.z()), 0, glFormat, glType, uploadData);
break;
default:
MGLOG_E("Unhandled texture target %s",
@@ -664,62 +774,69 @@ namespace MobileGL::MG_Backend::DirectGLES {
}
}
} else {
for (auto& uploadTarget : uploadTargets) {
for (SizeT level = 0; level < mipmapCount; ++level) {
auto levelTexelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level);
auto levelByteSize = textureMipmapObject->GetMipmapByteSize(uploadTarget, level);
bool levelDirty = textureMipmapObject->IsStorageDirty(uploadTarget, level);
auto glUploadTarget = MG_Util::ConvertTextureUploadTargetToGLEnum(uploadTarget);
auto* pData = (levelDirty && levelByteSize != 0)
? textureMipmapObject->MapMipmapData(uploadTarget, level)
: nullptr;
MGLOG_D(
"%s: target: %s: syncing mip %d: %dx%dx%d, byteSize = %d, pData = %p, levelDirty = %s",
__func__, MG_Util::ConvertTextureUploadTargetToString(uploadTarget).c_str(), level,
levelTexelSize.x(), levelTexelSize.y(), levelTexelSize.z(), levelByteSize, pData,
levelDirty ? "true" : "false");
ScopedDefaultUnpackState unpackState;
for (auto& uploadTarget : uploadTargets) {
for (SizeT level = 0; level < mipmapCount; ++level) {
auto levelTexelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level);
auto levelByteSize = textureMipmapObject->GetMipmapByteSize(uploadTarget, level);
bool levelDirty = textureMipmapObject->IsStorageDirty(uploadTarget, level);
auto glUploadTarget = MG_Util::ConvertTextureUploadTargetToGLEnum(uploadTarget);
auto* pData = (levelDirty && levelByteSize != 0)
? textureMipmapObject->MapMipmapData(uploadTarget, level)
: nullptr;
Vector<Float> convertedUploadData;
const void* uploadData = PrepareNorm16FloatFallbackUpload(
textureMipmapObject->GetFormat(), levelTexelSize, pData, levelByteSize, glType,
convertedUploadData);
MGLOG_D("%s: target: %s: syncing mip %d: %dx%dx%d, byteSize = %d, pData = %p, "
"levelDirty = %s",
__func__, MG_Util::ConvertTextureUploadTargetToString(uploadTarget).c_str(),
level, levelTexelSize.x(), levelTexelSize.y(), levelTexelSize.z(),
levelByteSize, pData, levelDirty ? "true" : "false");
DebugImpl::ErrorLopper::Clear();
g_GLESFuncs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
auto textureTarget = stateTextureObject->GetTarget();
// TODO: handle more texture types
switch (textureTarget) {
case TextureTarget::Texture2D:
case TextureTarget::TextureCubeMap: {
g_GLESFuncs.glTexImage2D(
glUploadTarget, static_cast<GLint>(level), (GLint)glInternalFormat,
static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()),
0, glFormat, glType, pData);
break;
DebugImpl::ErrorLopper::Clear();
g_GLESFuncs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
auto textureTarget = stateTextureObject->GetTarget();
// TODO: handle more texture types
switch (textureTarget) {
case TextureTarget::Texture2D:
case TextureTarget::TextureCubeMap: {
g_GLESFuncs.glTexImage2D(
glUploadTarget, static_cast<GLint>(level), (GLint)glInternalFormat,
static_cast<GLsizei>(levelTexelSize.x()),
static_cast<GLsizei>(levelTexelSize.y()), 0, glFormat, glType, uploadData);
break;
}
case TextureTarget::Texture3D: {
g_GLESFuncs.glTexImage3D(
glUploadTarget, static_cast<GLint>(level), (GLint)glInternalFormat,
static_cast<GLsizei>(levelTexelSize.x()),
static_cast<GLsizei>(levelTexelSize.y()),
static_cast<GLsizei>(levelTexelSize.z()), 0, glFormat, glType, uploadData);
break;
}
default: {
MGLOG_E("Unhandled texture target %s",
MG_Util::ConvertTextureTargetToString(textureTarget).c_str());
}
}
DebugImpl::ErrorLopper::Loop(
[file = __FILE__, line = __LINE__, func = __func__, glUploadTarget,
glInternalFormat, glFormat, glType, pData](GLenum err) {
MGLOG_D("%s(%s:%d) ES error: %s. glTexImage*: target=%s, internalformat=%s, "
"format=%s, type=%s, pixels=%p",
func, file, line, MG_Util::ConvertGLEnumToString(err).c_str(),
MG_Util::ConvertGLEnumToString(glUploadTarget).c_str(),
MG_Util::ConvertGLEnumToString(glInternalFormat).c_str(),
MG_Util::ConvertGLEnumToString(glFormat).c_str(),
MG_Util::ConvertGLEnumToString(glType).c_str(), pData);
});
MGLOG_D("Regenerated mipmap level %d for texture with ID: %u", level,
m_backendTextureId);
textureMipmapObject->MarkStorageDirty(uploadTarget, level, false);
}
case TextureTarget::Texture3D: {
g_GLESFuncs.glTexImage3D(
glUploadTarget, static_cast<GLint>(level), (GLint)glInternalFormat,
static_cast<GLsizei>(levelTexelSize.x()), static_cast<GLsizei>(levelTexelSize.y()),
static_cast<GLsizei>(levelTexelSize.z()), 0, glFormat, glType, pData);
break;
}
default: {
MGLOG_E("Unhandled texture target %s",
MG_Util::ConvertTextureTargetToString(textureTarget).c_str());
}
}
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__, func = __func__,
glUploadTarget, glInternalFormat, glFormat, glType,
pData](GLenum err) {
MGLOG_D("%s(%s:%d) ES error: %s. glTexImage*: target=%s, internalformat=%s, format=%s, "
"type=%s, pixels=%p",
func, file, line, MG_Util::ConvertGLEnumToString(err).c_str(),
MG_Util::ConvertGLEnumToString(glUploadTarget).c_str(),
MG_Util::ConvertGLEnumToString(glInternalFormat).c_str(),
MG_Util::ConvertGLEnumToString(glFormat).c_str(),
MG_Util::ConvertGLEnumToString(glType).c_str(), pData);
});
MGLOG_D("Regenerated mipmap level %d for texture with ID: %u", level, m_backendTextureId);
textureMipmapObject->MarkStorageDirty(uploadTarget, level, false);
}
}
}
m_isInitialized = true;
}
@@ -742,6 +859,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
TextureImpl::GenerateTextureFormatInfo(textureMipmapObject->GetFormat(), &glInternalFormat,
&glFormat, &glType);
const auto& uploadTargets = textureMipmapObject->GetUploadTargets();
ScopedDefaultUnpackState unpackState;
for (auto& uploadTarget : uploadTargets) {
for (SizeT level = 0; level < mipmapCount; ++level) {
if (!textureMipmapObject->IsStorageDirty(uploadTarget, level)) {
@@ -770,20 +888,24 @@ namespace MobileGL::MG_Backend::DirectGLES {
});
auto texelSize = textureMipmapObject->GetMipmapTexelSize(uploadTarget, level);
const void* mipData = textureMipmapObject->MapMipmapData(uploadTarget, level);
Vector<Float> convertedUploadData;
const void* uploadData = PrepareNorm16FloatFallbackUpload(
textureMipmapObject->GetFormat(), texelSize, mipData, byteSize, glType,
convertedUploadData);
switch (stateTextureObject->GetTarget()) {
case TextureTarget::Texture2D:
case TextureTarget::TextureCubeMap:
g_GLESFuncs.glTexSubImage2D(glUploadTarget, static_cast<GLint>(level), 0, 0,
static_cast<GLsizei>(texelSize.x()),
static_cast<GLsizei>(texelSize.y()), glFormat, glType,
mipData);
uploadData);
break;
case TextureTarget::Texture3D:
g_GLESFuncs.glTexSubImage3D(glUploadTarget, static_cast<GLint>(level), 0, 0, 0,
static_cast<GLsizei>(texelSize.x()),
static_cast<GLsizei>(texelSize.y()),
static_cast<GLsizei>(texelSize.z()), glFormat, glType,
mipData);
uploadData);
break;
default:
MGLOG_E("Unhandled texture target %s",
@@ -52,6 +52,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
return const_cast<StateBackendObjectRegistry*>(this)->find(stateObj);
}
iterator begin() { return m_backendObjects.begin(); }
const_iterator begin() const { return m_backendObjects.begin(); }
iterator end() { return m_backendObjects.end(); }
const_iterator end() const { return m_backendObjects.end(); }
+4 -2
View File
@@ -26,8 +26,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
#endif
using namespace MobileGL::MG_Util::TextureFormatProcessor;
auto options = (g_GLESCapabilities.SupportsNorm16Texture) ? PixelFormatNormalizeOptionBit::None
: PixelFormatNormalizeOptionBit::NoNorm16;
const Bool useNorm16Texture = g_GLESCapabilities.SupportsNorm16Texture &&
g_GLESCapabilities.GLESRendererString.find("ANGLE") == String::npos;
auto options =
useNorm16Texture ? PixelFormatNormalizeOptionBit::None : PixelFormatNormalizeOptionBit::NoNorm16;
NormalizePixelFormat(MG_Util::ConvertTextureInternalFormatToGLEnum(internalFormat), options,
outInternalFormat, outFormat, outType);
}
@@ -41,6 +41,26 @@ namespace MobileGL::MG_Util::TextureFormatProcessor {
*outInternalFormat = GL_R32F;
break;
}
case GL_RGBA16_SNORM:
if (options & PixelFormatNormalizeOptionBit::NoNorm16) {
*outInternalFormat = GL_RGBA16F;
break;
}
case GL_RGB16_SNORM:
if (options & PixelFormatNormalizeOptionBit::NoNorm16) {
*outInternalFormat = GL_RGB16F;
break;
}
case GL_RG16_SNORM:
if (options & PixelFormatNormalizeOptionBit::NoNorm16) {
*outInternalFormat = GL_RG16F;
break;
}
case GL_R16_SNORM:
if (options & PixelFormatNormalizeOptionBit::NoNorm16) {
*outInternalFormat = GL_R16F;
break;
}
default:
*outInternalFormat = internalFormat;
break;
@@ -235,8 +255,13 @@ namespace MobileGL::MG_Util::TextureFormatProcessor {
case GL_RGB16_SNORM:
case GL_RG16_SNORM:
case GL_R16_SNORM:
*outType = GL_SHORT;
break;
if (options & PixelFormatNormalizeOptionBit::NoNorm16) {
*outType = GL_FLOAT;
break;
} else {
*outType = GL_SHORT;
break;
}
case GL_RGBA8_SNORM:
case GL_RGB8_SNORM:
case GL_RG8_SNORM: