Files
MobileGL/MobileGL/MG_Impl/GLImpl/Texture/Validators.h
T

119 lines
7.8 KiB
C++

// MobileGL - MobileGL/MG_Impl/GLImpl/Texture/Validators.h
// Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0:
// https://www.gnu.org/licenses/gpl-3.0.txt
// https://www.gnu.org/licenses/lgpl-3.0.txt
// SPDX-License-Identifier: LGPL-3.0-only
// End of Source File Header
#pragma once
#include "MG_State/GLState/TextureState/TextureEnum.h"
#include "MG_Util/Types.h"
#include <Includes.h>
#include <MG_State/GLState/TextureState/TextureObject.h>
namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
Bool ValidateTextureTarget(TextureTarget target);
Bool ValidateTextureUploadTarget(TextureUploadTarget textureUploadTarget);
Bool ValidateTextureName(Uint texture, Bool allowZero = false);
Bool ValidateTextureInputFormat(TextureInputFormat format);
Bool ValidateTexturePixelDataType(TexturePixelDataType texturePixelDataType);
Bool ValidateTextureLevelNumber(Int level);
Bool ValidateTextureSizeWithTextureUploadTarget(TextureUploadTarget target, GLsizei width, GLsizei height);
// The two shape rules a cube-map-array level owes (GL 4.6 core 8.5): its faces are square, and
// its depth counts whole cubes. Both are GL_INVALID_VALUE. This used to be spelled inline in
// glTexStorage3D only, which is why glTexImage3D let both violations through - every entry
// point that DEFINES a cube-array level calls this now, so the two cannot drift again. A
// non-cube-array upload target answers true untouched.
Bool ValidateCubeMapArrayShape(TextureUploadTarget target, GLsizei width, GLsizei height, GLsizei depth,
const char* caller);
Bool ValidateTextureSizeRange(Int width, Int height, Int depth);
Bool ValidateTextureInternalFormat(TextureInternalFormat format);
Bool ValidateTextureBorderNumber(Int border);
Bool IsIntegerColorInputFormat(TextureInputFormat format);
Bool IsIntegerColorInternalFormat(TextureInternalFormat internalFormat);
Bool ValidateClientFormatTypePairing(TextureInputFormat format, TexturePixelDataType type);
Bool ValidateTextureInternalFormatCompatibleWithInput(TextureInputFormat format,
TextureInternalFormat internalFormat,
TexturePixelDataType type);
Bool ValidateTextureLevelWithUploadTarget(TextureUploadTarget target, Int level);
// "Is <level> a level this texture actually has?", which ValidateTextureLevelNumber above
// does NOT answer - that one only bounds the index by GL_MAX_TEXTURE_SIZE and knows nothing
// about the object. Entry points that resolve a level straight into a backend image
// subresource need this one: a level the texture never had is GL_INVALID_VALUE (GL 4.6 core
// 18.3.2), and passing it through instead reaches the driver as an out-of-range subresource.
// Note the error split is per-entry-point, so this is not universally reusable:
// glClearTexImage owes INVALID_OPERATION for the same out-of-range level and spells its own
// copy of this predicate in GL_Texture.cpp (GetClearTextureObject).
Bool ValidateTextureLevelExists(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject, Int level,
const char* caller);
Bool ValidateTextureObject(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject);
// Rejects the per-target default texture objects (name 0) with GL_INVALID_OPERATION for entry
// points that require a GenTextures-created texture, e.g. TexStorage* ("An INVALID_OPERATION
// error is generated if zero is bound to target", ARB_texture_storage).
Bool ValidateTextureNotDefault(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
const char* caller);
Bool ValidateTextureTargetUniformity(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
TextureTarget target);
Bool ValidateTextureSubImageOffsets(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject, Int xoffset,
Int width, Int yoffset = 0, Int height = 0, Int zoffset = 0, Int depth = 0);
// The texel block of one glCopyImageSubData endpoint, resolved to the two things the
// compatibility rule actually asks about. `compressed` is not redundant with a block bigger
// than 1x1: it is what distinguishes "compressed, and so the region is measured in texels of
// a blocked image" from "uncompressed, and so it is measured in texels".
struct CopyImageTexelBlock {
SizeT byteSize = 0;
Uint blockWidth = 1;
Uint blockHeight = 1;
Bool compressed = false;
};
// `compressedFormat` is the GLenum a glCompressedTexImage* upload recorded for the level, or
// GL_NONE. It has to be asked for separately because MobileGL stores every compressed format
// in uncompressed storage (ConvertGLEnumToTextureInternalFormat), so the TextureInternalFormat
// alone can no longer tell a BPTC image from the RGBA8 backing it.
CopyImageTexelBlock ResolveCopyImageTexelBlock(TextureInternalFormat format, GLenum compressedFormat);
// GL 4.6 core 18.3.2: the two images must be COMPATIBLE, and compatible means their texel
// blocks are the same SIZE - not that they share a base internal format. RGBA32UI into
// RGBA32F is legal (both 128-bit) while RGBA8 into RGBA32F is not, and a compressed image
// pairs with an uncompressed one whose texel is as big as the compressed block.
Bool ValidateCopyImageFormatCompatibility(const CopyImageTexelBlock& srcBlock,
const CopyImageTexelBlock& dstBlock);
// GL 4.6 core 18.3.2: for a compressed image the region's origin must sit on a block
// boundary and its size must be a whole number of blocks - unless the edge it runs to is
// the edge of the image.
Bool ValidateCopyImageBlockAlignment(const CopyImageTexelBlock& block, Int x, Int y, Int width, Int height,
Int imageWidth, Int imageHeight, const char* endpointName);
// GL 4.6 SS 8.6 subset rule for glCopyTexImage*: the read buffer must supply every component
// the requested internalformat asks for, but may supply more.
Bool ValidateCopyTexImageBaseFormatSubset(TextureInternalFormat destFormat, TextureInternalFormat srcFormat);
// ---- glTextureView (ARB_texture_view / GL 4.6 core 8.18) ----
// Table 8.21's view classes. `None` is not a class - it means the format has NO entry in the
// table, which the spec turns into a much stricter rule than "same class": such a format can
// only ever be viewed as ITSELF. Every depth, stencil and depth/stencil format lands here,
// which is why the Better Clouds D24S8 view must name GL_DEPTH24_STENCIL8 exactly.
enum class TextureViewClass {
None = 0,
Bits128,
Bits96,
Bits64,
Bits48,
Bits32,
Bits24,
Bits16,
Bits8,
Rgtc1Red,
Rgtc2Rg,
BptcUnorm,
BptcFloat,
};
TextureViewClass GetTextureViewClass(GLenum internalformat);
// Table 8.20: which <target> values glTextureView accepts for a given origtexture target.
Bool IsLegalTextureViewTargetPair(TextureTarget origTarget, TextureTarget viewTarget);
// Table 8.20 again, read the other way: how many layers <target> requires. Returns 0 for the
// targets whose layer count is unconstrained (the array targets), 6 for GL_TEXTURE_CUBE_MAP,
// and 1 for every single-layer target. GL_TEXTURE_CUBE_MAP_ARRAY is special-cased by the
// caller because its constraint is "a multiple of 6", not an exact count.
Uint RequiredTextureViewLayerCount(TextureTarget viewTarget);
} // namespace MobileGL::MG_Impl::GLImpl::TextureImpl