mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 20:28:32 +09:00
[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:
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user