mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +09:00
[Fix] (MG_Impl/GLImpl, MG_Backend): fix piglit texture and buffer cases
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user