[Fix] (MG_Impl/GLImpl, MG_Backend): fix piglit texture and buffer cases

This commit is contained in:
2026-07-03 08:51:22 +08:00
parent 5cdc6c902e
commit 51d9fa91ed
12 changed files with 249 additions and 44 deletions
+12
View File
@@ -346,6 +346,18 @@ target_compile_definitions(${CMAKE_PROJECT_NAME}
MOBILEGL_LOG_ACTIVE_LEVEL=${MOBILEGL_LOG_ACTIVE_LEVEL}
)
if(UNIX AND NOT APPLE AND NOT ANDROID)
foreach(MOBILEGL_LOADER_ALIAS
libEGL.so libEGL.so.1)
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E create_symlink
"$<TARGET_FILE_NAME:${CMAKE_PROJECT_NAME}>"
"$<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/${MOBILEGL_LOADER_ALIAS}"
COMMENT "Creating ${MOBILEGL_LOADER_ALIAS} alias for Linux GL/EGL loaders"
)
endforeach()
endif()
if(NOT ANDROID)
add_library(${CMAKE_PROJECT_NAME}_s STATIC
${SOURCE_FILES}
@@ -906,7 +906,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
m_dynamicParameters.MaxTextureBufferSize = m_GLESCapabilities.MaxTextureBufferSize;
m_dynamicParameters.MaxUniformBufferBindings = m_GLESCapabilities.MaxUniformBufferBindings;
m_dynamicParameters.MaxUniformBlockSize = m_GLESCapabilities.MaxUniformBlockSize;
m_dynamicParameters.MaxImageUnits = m_GLESCapabilities.MaxImageUnits;
const Int maxSupportedTextureUnits =
static_cast<Int>(MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS);
m_dynamicParameters.MaxImageUnits = std::min(m_GLESCapabilities.MaxImageUnits, maxSupportedTextureUnits);
m_dynamicParameters.MaxCombinedImageUniforms = m_GLESCapabilities.MaxCombinedImageUniforms;
m_dynamicParameters.MaxComputeImageUniforms = m_GLESCapabilities.MaxComputeImageUniforms;
m_dynamicParameters.MaxDrawBuffers = m_GLESCapabilities.MaxDrawBuffers;
@@ -2698,6 +2698,94 @@ namespace MobileGL::MG_Backend::DirectGLES {
}
};
static SizeT AlignPixelRow(SizeT rowBytes, Int alignment) {
const SizeT resolvedAlignment = static_cast<SizeT>(std::max(alignment, 1));
return (rowBytes + resolvedAlignment - 1) & ~(resolvedAlignment - 1);
}
static Int GetFloatReadbackChannelCount(GLenum format) {
switch (format) {
case GL_RED:
return 1;
case GL_RGBA:
return 4;
default:
return 0;
}
}
static Bool ReadPixelsFloatViaUnsignedByte(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
void* pixels) {
if (width <= 0 || height <= 0) {
return true;
}
const Int dstChannels = GetFloatReadbackChannelCount(format);
if (dstChannels == 0) {
return false;
}
const GLenum readFormat = format == GL_RED ? GL_RED : GL_RGBA;
const Int readChannels = format == GL_RED ? 1 : 4;
Vector<Uint8> raw(static_cast<SizeT>(width) * static_cast<SizeT>(height) *
static_cast<SizeT>(readChannels));
GLint prevPixelPackBuffer = 0;
g_GLESFuncs.glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &prevPixelPackBuffer);
g_GLESFuncs.glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
g_GLESFuncs.glPixelStorei(GL_PACK_ALIGNMENT, 1);
g_GLESFuncs.glPixelStorei(GL_PACK_ROW_LENGTH, 0);
g_GLESFuncs.glPixelStorei(GL_PACK_SKIP_ROWS, 0);
g_GLESFuncs.glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
g_GLESFuncs.glReadPixels(x, y, width, height, readFormat, GL_UNSIGNED_BYTE, raw.data());
const GLenum readError = g_GLESFuncs.glGetError();
g_GLESFuncs.glBindBuffer(GL_PIXEL_PACK_BUFFER, static_cast<GLuint>(prevPixelPackBuffer));
if (readError != GL_NO_ERROR) {
MGLOG_E("ReadPixels: GL_FLOAT fallback read failed: %s",
MG_Util::ConvertGLEnumToString(readError).c_str());
return true;
}
const auto packParams = MG_State::pGLContext->GetPixelStoreParameters(false);
const SizeT rowPixels = static_cast<SizeT>(packParams.RowLength > 0 ? packParams.RowLength : width);
const SizeT dstPixelBytes = static_cast<SizeT>(dstChannels) * sizeof(Float);
const SizeT dstRowStride = AlignPixelRow(rowPixels * dstPixelBytes, packParams.Alignment);
const SizeT dstOffset = static_cast<SizeT>(std::max(packParams.SkipRows, 0)) * dstRowStride +
static_cast<SizeT>(std::max(packParams.SkipPixels, 0)) * dstPixelBytes;
const SizeT packedSize = dstOffset + static_cast<SizeT>(height - 1) * dstRowStride +
static_cast<SizeT>(width) * dstPixelBytes;
Vector<Uint8> packed(packedSize, 0);
for (GLsizei row = 0; row < height; ++row) {
const Uint8* srcRow = raw.data() + static_cast<SizeT>(row) * static_cast<SizeT>(width) *
static_cast<SizeT>(readChannels);
auto* dstRow = reinterpret_cast<Float*>(packed.data() + dstOffset +
static_cast<SizeT>(row) * dstRowStride);
for (GLsizei col = 0; col < width; ++col) {
const Uint8* src = srcRow + static_cast<SizeT>(col) * static_cast<SizeT>(readChannels);
Float* dst = dstRow + static_cast<SizeT>(col) * static_cast<SizeT>(dstChannels);
// TODO: extend readback packing to all desktop GL read formats instead of only normalized RED/RGBA.
for (Int component = 0; component < dstChannels; ++component) {
dst[component] = static_cast<Float>(src[component]) / 255.0f;
}
}
}
const auto& pixelPackBufferObject =
MG_State::pGLContext->GetBufferBindingSlot(BufferTarget::PixelPack).GetBoundObject();
if (pixelPackBufferObject) {
const SizeT pboOffset = reinterpret_cast<SizeT>(pixels);
if (pboOffset + packed.size() > pixelPackBufferObject->GetSize()) {
MGLOG_E("ReadPixels: GL_FLOAT fallback PBO is too small");
return true;
}
pixelPackBufferObject->UploadSubData({packed.data(), packed.size()}, pboOffset);
pixelPackBufferObject->ClearDirty();
} else if (pixels != nullptr && !packed.empty()) {
Memcpy(pixels, packed.data(), packed.size());
}
return true;
}
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) {
MGLOG_D("ReadPixels: x=%d y=%d w=%d h=%d format=%s type=%s pixels=%p", x, y, width, height,
MG_Util::ConvertGLEnumToString(format).c_str(), MG_Util::ConvertGLEnumToString(type).c_str(), pixels);
@@ -2732,6 +2820,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
MGLOG_E("ReadPixels: bound READ FBO is not complete");
return;
}
if (type == GL_FLOAT && ReadPixelsFloatViaUnsignedByte(x, y, width, height, format, pixels)) {
MGLOG_D("ReadPixels: finished via GL_FLOAT fallback");
return;
}
// Handle PBO
auto& pixelPackBufferObject =
@@ -690,7 +690,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
m_dynamicParameters.MaxTextureBufferSize = m_vulkanCaps.MaxTextureBufferSize;
m_dynamicParameters.MaxUniformBufferBindings = m_vulkanCaps.MaxUniformBufferBindings;
m_dynamicParameters.MaxUniformBlockSize = m_vulkanCaps.MaxUniformBlockSize;
m_dynamicParameters.MaxImageUnits = m_vulkanCaps.MaxImageUnits;
m_dynamicParameters.MaxImageUnits = std::min(m_vulkanCaps.MaxImageUnits, maxSupportedTextureUnits);
m_dynamicParameters.MaxCombinedImageUniforms = m_vulkanCaps.MaxCombinedImageUniforms;
m_dynamicParameters.MaxComputeImageUniforms = m_vulkanCaps.MaxComputeImageUniforms;
const Int maxSupportedDrawBuffers =
@@ -1041,38 +1041,46 @@ void main() {
}
static Bool EnsureGenerateMipmapStorageAllocated(::MobileGL::MG_State::GLState::TextureObjectMipmap& texture,
::MobileGL::TextureUploadTarget uploadTarget,
Uint32 baseMipLevel) {
const Uint32 existingMipLevelCount = static_cast<Uint32>(texture.GetMipmapLevelCount());
if (existingMipLevelCount <= baseMipLevel) {
return false;
}
const IntVec3 baseTexelSize = texture.GetMipmapTexelSize(uploadTarget, baseMipLevel);
const SizeT baseByteSize = texture.GetMipmapByteSize(uploadTarget, baseMipLevel);
if (baseTexelSize.x() <= 0 || baseTexelSize.y() <= 0 || baseTexelSize.z() <= 0 || baseByteSize == 0) {
const auto& uploadTargets = texture.GetUploadTargets();
if (uploadTargets.empty()) {
return false;
}
const SizeT baseTexelCount = static_cast<SizeT>(baseTexelSize.x()) * static_cast<SizeT>(baseTexelSize.y()) *
static_cast<SizeT>(baseTexelSize.z());
if (baseTexelCount == 0 || (baseByteSize % baseTexelCount) != 0) {
return false;
}
for (const auto uploadTarget : uploadTargets) {
const IntVec3 baseTexelSize = texture.GetMipmapTexelSize(uploadTarget, baseMipLevel);
const SizeT baseByteSize = texture.GetMipmapByteSize(uploadTarget, baseMipLevel);
if (baseTexelSize.x() <= 0 || baseTexelSize.y() <= 0 || baseTexelSize.z() <= 0 ||
baseByteSize == 0) {
return false;
}
const SizeT bytesPerTexel = baseByteSize / baseTexelCount;
const Uint32 requiredMipLevelCount = baseMipLevel + ComputeFullMipLevelCount(baseTexelSize);
if (existingMipLevelCount >= requiredMipLevelCount) {
return true;
}
const SizeT baseTexelCount = static_cast<SizeT>(baseTexelSize.x()) *
static_cast<SizeT>(baseTexelSize.y()) *
static_cast<SizeT>(baseTexelSize.z());
if (baseTexelCount == 0 || (baseByteSize % baseTexelCount) != 0) {
return false;
}
for (Uint32 level = existingMipLevelCount; level < requiredMipLevelCount; ++level) {
const IntVec3 levelTexelSize = ComputeMipTexelSize(baseTexelSize, level - baseMipLevel);
const SizeT levelByteSize = bytesPerTexel * static_cast<SizeT>(levelTexelSize.x()) *
static_cast<SizeT>(levelTexelSize.y()) *
static_cast<SizeT>(levelTexelSize.z());
texture.AllocateStorage(uploadTarget, level, {levelTexelSize, levelByteSize});
texture.MarkStorageDirty(uploadTarget, level, false);
const SizeT bytesPerTexel = baseByteSize / baseTexelCount;
const Uint32 requiredMipLevelCount = baseMipLevel + ComputeFullMipLevelCount(baseTexelSize);
if (existingMipLevelCount >= requiredMipLevelCount) {
continue;
}
for (Uint32 level = existingMipLevelCount; level < requiredMipLevelCount; ++level) {
const IntVec3 levelTexelSize = ComputeMipTexelSize(baseTexelSize, level - baseMipLevel);
const SizeT levelByteSize = bytesPerTexel * static_cast<SizeT>(levelTexelSize.x()) *
static_cast<SizeT>(levelTexelSize.y()) *
static_cast<SizeT>(levelTexelSize.z());
texture.AllocateStorage(uploadTarget, level, {levelTexelSize, levelByteSize});
texture.MarkStorageDirty(uploadTarget, level, false);
}
}
return true;
}
@@ -1696,12 +1704,47 @@ void main() {
}
}
static void StoreReadbackPixelFloat(const Uint8* src, Bool srcIsBgra, GLenum dstFormat, Float* dst) {
const Float r = static_cast<Float>(srcIsBgra ? src[2] : src[0]) / 255.0f;
const Float g = static_cast<Float>(src[1]) / 255.0f;
const Float b = static_cast<Float>(srcIsBgra ? src[0] : src[2]) / 255.0f;
const Float a = static_cast<Float>(src[3]) / 255.0f;
// TODO: extend readback packing to integer/depth formats instead of only normalized color formats.
switch (dstFormat) {
case GL_RGB:
dst[0] = r;
dst[1] = g;
dst[2] = b;
break;
case GL_BGR:
dst[0] = b;
dst[1] = g;
dst[2] = r;
break;
case GL_RGBA:
dst[0] = r;
dst[1] = g;
dst[2] = b;
dst[3] = a;
break;
case GL_BGRA:
dst[0] = b;
dst[1] = g;
dst[2] = r;
dst[3] = a;
break;
default:
break;
}
}
static Bool PackReadbackToClientOrPbo(const Uint8* srcPixels, VkFormat srcFormat, GLsizei width,
GLsizei height, GLenum format, GLenum type, void* pixels) {
if (width <= 0 || height <= 0) {
return true;
}
if (type != GL_UNSIGNED_BYTE) {
if (type != GL_UNSIGNED_BYTE && type != GL_FLOAT) {
MGLOG_E("DirectVulkan readback skipped: unsupported type=0x%x", type);
return false;
}
@@ -1713,15 +1756,16 @@ void main() {
}
const auto packParams = MG_State::pGLContext->GetPixelStoreParameters(false);
const SizeT dstComponentBytes = type == GL_FLOAT ? sizeof(Float) : sizeof(Uint8);
const SizeT rowPixels = static_cast<SizeT>(packParams.RowLength > 0 ? packParams.RowLength : width);
const SizeT dstRowStride = AlignPixelRow(rowPixels * static_cast<SizeT>(dstChannels),
const SizeT dstRowStride = AlignPixelRow(rowPixels * static_cast<SizeT>(dstChannels) * dstComponentBytes,
packParams.Alignment);
const SizeT dstOffset = static_cast<SizeT>(std::max(packParams.SkipRows, 0)) * dstRowStride +
static_cast<SizeT>(std::max(packParams.SkipPixels, 0)) *
static_cast<SizeT>(dstChannels);
static_cast<SizeT>(dstChannels) * dstComponentBytes;
const SizeT packedSize = dstOffset +
(static_cast<SizeT>(height - 1) * dstRowStride) +
(static_cast<SizeT>(width) * static_cast<SizeT>(dstChannels));
(static_cast<SizeT>(width) * static_cast<SizeT>(dstChannels) * dstComponentBytes);
Vector<Uint8> packed(packedSize, 0);
const Bool srcIsBgra = IsBgraVkFormat(srcFormat);
@@ -1729,10 +1773,14 @@ void main() {
const Uint8* srcRow = srcPixels + static_cast<SizeT>(row) * static_cast<SizeT>(width) * 4;
Uint8* dstRow = packed.data() + dstOffset + static_cast<SizeT>(row) * dstRowStride;
for (GLsizei col = 0; col < width; ++col) {
StoreReadbackPixel(srcRow + static_cast<SizeT>(col) * 4,
srcIsBgra,
format,
dstRow + static_cast<SizeT>(col) * static_cast<SizeT>(dstChannels));
const auto* src = srcRow + static_cast<SizeT>(col) * 4;
auto* dst = dstRow + static_cast<SizeT>(col) * static_cast<SizeT>(dstChannels) *
dstComponentBytes;
if (type == GL_FLOAT) {
StoreReadbackPixelFloat(src, srcIsBgra, format, reinterpret_cast<Float*>(dst));
} else {
StoreReadbackPixel(src, srcIsBgra, format, dst);
}
}
}
@@ -4854,9 +4902,9 @@ void main() {
void VulkanRenderer::GenerateMipmap(GLenum target) {
const auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
const auto uploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
MOBILEGL_ASSERT(textureTarget == TextureTarget::Texture2D || textureTarget == TextureTarget::Texture3D,
"GenerateMipmap currently only supports GL_TEXTURE_2D and GL_TEXTURE_3D.");
MOBILEGL_ASSERT(textureTarget == TextureTarget::Texture2D || textureTarget == TextureTarget::Texture3D ||
textureTarget == TextureTarget::TextureCubeMap,
"GenerateMipmap currently only supports GL_TEXTURE_2D, GL_TEXTURE_3D, and GL_TEXTURE_CUBE_MAP.");
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
auto texture = textureUnit.GetBindingSlot(textureTarget).GetBoundObject();
@@ -4908,8 +4956,7 @@ void main() {
"GenerateMipmap: depth-stencil mipmap generation is not supported yet.");
}
const Bool allocatedMipmapStorage =
EnsureGenerateMipmapStorageAllocated(*mipmapTexture, uploadTarget, baseMipLevel);
const Bool allocatedMipmapStorage = EnsureGenerateMipmapStorageAllocated(*mipmapTexture, baseMipLevel);
MOBILEGL_ASSERT(allocatedMipmapStorage, "GenerateMipmap could not allocate a full mip chain for this texture.");
resource = m_textureManager->SyncTextureAndGetDescriptor(*texture);
@@ -5021,13 +5068,13 @@ void main() {
blitRegion.srcSubresource.aspectMask = resource->aspect;
blitRegion.srcSubresource.mipLevel = level - 1;
blitRegion.srcSubresource.baseArrayLayer = 0;
blitRegion.srcSubresource.layerCount = 1;
blitRegion.srcSubresource.layerCount = resource->arrayLayers;
blitRegion.srcOffsets[0] = {0, 0, 0};
blitRegion.srcOffsets[1] = {srcTexelSize.x(), srcTexelSize.y(), srcTexelSize.z()};
blitRegion.dstSubresource.aspectMask = resource->aspect;
blitRegion.dstSubresource.mipLevel = level;
blitRegion.dstSubresource.baseArrayLayer = 0;
blitRegion.dstSubresource.layerCount = 1;
blitRegion.dstSubresource.layerCount = resource->arrayLayers;
blitRegion.dstOffsets[0] = {0, 0, 0};
blitRegion.dstOffsets[1] = {dstTexelSize.x(), dstTexelSize.y(), dstTexelSize.z()};
@@ -1266,6 +1266,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_Util::ConvertGLEnumToString(target).c_str(), pointIndex, buffer);
BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target);
if (!BufferImpl::ValidateBufferBindingPointTarget(bufferTarget)) return;
if (!BufferImpl::ValidateBufferBindingPointIndex(bufferTarget, pointIndex)) return;
auto& point = MG_State::pGLContext->GetBufferBindingPoint(bufferTarget, pointIndex);
SharedPtr<MG_State::GLState::BufferObject> bufferObject;
@@ -1297,6 +1298,7 @@ namespace MobileGL::MG_Impl::GLImpl {
MG_Util::ConvertGLEnumToString(target).c_str(), index, buffer, offset, size);
BufferTarget bufferTarget = MG_Util::ConvertGLEnumToBufferTarget(target);
if (!BufferImpl::ValidateBufferBindingPointTarget(bufferTarget)) return;
if (!BufferImpl::ValidateBufferBindingPointIndex(bufferTarget, index)) return;
auto& point = MG_State::pGLContext->GetBufferBindingPoint(bufferTarget, index);
SharedPtr<MG_State::GLState::BufferObject> bufferObject;
@@ -7,6 +7,7 @@
// End of Source File Header
#include "Validators.h"
#include <MG_Backend/BackendObjects.h>
#include <MG_State/GLState/Core.h>
#include <MG_State/GLState/ErrorState/Error.h>
#include <MG_Util/Converters/GLToStr/GLEnumConverter.h>
@@ -52,6 +53,26 @@ namespace MobileGL::MG_Impl::GLImpl::BufferImpl {
return true;
}
Bool ValidateBufferBindingPointIndex(BufferTarget target, Uint index) {
SizeT pointCount = MG_State::pGLContext->GetBufferBindingPointCount(target);
if (target == BufferTarget::ShaderStorage && MG_Backend::pActiveBackendObject) {
const Int backendCount =
MG_Backend::pActiveBackendObject->GetDynamicParameters().MaxShaderStorageBufferBindings;
pointCount = std::min(pointCount, static_cast<SizeT>(std::max(backendCount, 0)));
}
if (index < pointCount) {
return true;
}
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl/BufferImpl", "ValidateBufferBindingPointIndex",
std::format("Binding point index {} is out of range for target {}.", index,
MG_Util::ConvertBufferTargetToString(target))));
return false;
}
Bool ValidateBufferName(Uint index, Bool allowZero) {
if (index == 0) {
if (allowZero) return true;
@@ -16,4 +16,5 @@ namespace MobileGL::MG_Impl::GLImpl::BufferImpl {
Bool ValidateBufferUsage(BufferUsage usage);
Bool ValidateBufferMappingAccess(Flags<BufferMappingAccessBit> accessBits);
Bool ValidateBufferBindingPointTarget(BufferTarget target);
Bool ValidateBufferBindingPointIndex(BufferTarget target, Uint index);
} // namespace MobileGL::MG_Impl::GLImpl::BufferImpl
@@ -235,6 +235,25 @@ namespace MobileGL::MG_Impl::GLImpl {
return true;
}
bool ValidateShaderStorageBlockBinding(GLuint binding) {
SizeT maxBindingCount = MG_State::pGLContext->GetBufferBindingPointCount(BufferTarget::ShaderStorage);
if (MG_Backend::pActiveBackendObject) {
const Int backendCount =
MG_Backend::pActiveBackendObject->GetDynamicParameters().MaxShaderStorageBufferBindings;
maxBindingCount = std::min(maxBindingCount, static_cast<SizeT>(std::max(backendCount, 0)));
}
if (binding < maxBindingCount) {
return true;
}
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
"Shader storage block binding is out of range."));
return false;
}
void AttachShader_State(GLuint program, GLuint shader) {
auto& programObject = TryToGetProgramObject(program);
if (!programObject) return;
@@ -1973,6 +1992,7 @@ namespace MobileGL::MG_Impl::GLImpl {
void ShaderStorageBlockBinding(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding) {
auto& programObject = TryToGetProgramObject(program);
if (!programObject || !programObject->GetLinkStatus()) return;
if (!ValidateShaderStorageBlockBinding(storageBlockBinding)) return;
auto shaderStorageBlockBinding = MG_Backend::gBackendFunctionsTable.GL.ShaderStorageBlockBinding;
if (!shaderStorageBlockBinding) {
MG_State::pGLContext->RecordError(
+12 -4
View File
@@ -3218,13 +3218,21 @@ namespace MobileGL::MG_Impl::GLImpl {
void GenerateMipmap(GLenum target) {
const auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
if (!TextureImpl::ValidateTextureTarget(textureTarget)) {
return;
}
auto& activeUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit());
auto& textureObject = activeUnit.GetBindingSlot(textureTarget).GetBoundObject();
if (textureObject) {
auto* mipmapTexture = dynamic_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
MOBILEGL_ASSERT(mipmapTexture != nullptr, "GenerateMipmap requires mipmap texture storage.");
EnsureGeneratedMipmapStorageAllocated(*mipmapTexture);
if (!textureObject) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "GenerateMipmap requires a bound texture."));
return;
}
auto* mipmapTexture = dynamic_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
MOBILEGL_ASSERT(mipmapTexture != nullptr, "GenerateMipmap requires mipmap texture storage.");
EnsureGeneratedMipmapStorageAllocated(*mipmapTexture);
GenerateMipmap_Backend(target);
}
@@ -99,7 +99,7 @@ namespace MobileGL::MG_State::GLState {
}
for (auto& imageBinding : m_imageTextureBindings) {
if (imageBinding.Texture == it->second) {
imageBinding.Bind(nullptr, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
imageBinding.Bind(nullptr, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R8);
}
}
m_textureObjects.erase(it);
@@ -20,7 +20,7 @@ namespace MobileGL::MG_State::GLState {
GLboolean Layered = GL_FALSE;
GLint Layer = 0;
GLenum Access = GL_READ_ONLY;
GLenum Format = GL_RGBA8;
GLenum Format = GL_R8;
Uint16 Version = 0;
void Bind(SharedPtr<ITextureObject> texture, GLint level, GLboolean layered, GLint layer, GLenum access,