mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +09:00
[Fix] (Texture): cube-map-array shape rules on glTexImage3D, GL_TEXTURE_SHARED_SIZE, and the unimplemented glCopyTexSubImage1D/3D
This commit is contained in:
@@ -339,6 +339,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
return GetTextureComponentType(textureInternalFormat, componentSizes.Alpha, false, false);
|
return GetTextureComponentType(textureInternalFormat, componentSizes.Alpha, false, false);
|
||||||
case GL_TEXTURE_DEPTH_TYPE:
|
case GL_TEXTURE_DEPTH_TYPE:
|
||||||
return GetTextureComponentType(textureInternalFormat, componentSizes.Depth, true, false);
|
return GetTextureComponentType(textureInternalFormat, componentSizes.Depth, true, false);
|
||||||
|
case GL_TEXTURE_SHARED_SIZE:
|
||||||
|
// GL 4.6 core table 8.24: the size in bits of the SHARED EXPONENT, which only the
|
||||||
|
// one shared-exponent format has. Everything else answers zero, and the
|
||||||
|
// conformance suite compares "at least", not "equal".
|
||||||
|
return textureInternalFormat == TextureInternalFormat::RGB9E5 ? 5 : 0;
|
||||||
default:
|
default:
|
||||||
MOBILEGL_ASSERT(false, "Invalid texture level component pname: %d", pname);
|
MOBILEGL_ASSERT(false, "Invalid texture level component pname: %d", pname);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2214,6 +2219,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return;
|
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return;
|
||||||
if (!TextureImpl::ValidateTextureLevelNumber(level)) return;
|
if (!TextureImpl::ValidateTextureLevelNumber(level)) return;
|
||||||
if (!TextureImpl::ValidateTextureSizeWithTextureUploadTarget(textureUploadTarget, width, height)) return;
|
if (!TextureImpl::ValidateTextureSizeWithTextureUploadTarget(textureUploadTarget, width, height)) return;
|
||||||
|
if (!TextureImpl::ValidateCubeMapArrayShape(textureUploadTarget, width, height, depth, __func__)) return;
|
||||||
if (!TextureImpl::ValidateTextureSizeRange(width, height, depth)) return;
|
if (!TextureImpl::ValidateTextureSizeRange(width, height, depth)) return;
|
||||||
if (!TextureImpl::ValidateTextureInternalFormat(textureInternalFormat)) return;
|
if (!TextureImpl::ValidateTextureInternalFormat(textureInternalFormat)) return;
|
||||||
if (!TextureImpl::ValidateTextureBorderNumber(border)) return;
|
if (!TextureImpl::ValidateTextureBorderNumber(border)) return;
|
||||||
@@ -3307,6 +3313,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
case GL_TEXTURE_ALPHA_SIZE:
|
case GL_TEXTURE_ALPHA_SIZE:
|
||||||
case GL_TEXTURE_DEPTH_SIZE:
|
case GL_TEXTURE_DEPTH_SIZE:
|
||||||
case GL_TEXTURE_STENCIL_SIZE:
|
case GL_TEXTURE_STENCIL_SIZE:
|
||||||
|
case GL_TEXTURE_SHARED_SIZE:
|
||||||
if (params) {
|
if (params) {
|
||||||
*params = GetTextureLevelComponentParameter(textureObject->GetFormat(), pname);
|
*params = GetTextureLevelComponentParameter(textureObject->GetFormat(), pname);
|
||||||
}
|
}
|
||||||
@@ -3479,6 +3486,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
case GL_TEXTURE_ALPHA_SIZE:
|
case GL_TEXTURE_ALPHA_SIZE:
|
||||||
case GL_TEXTURE_DEPTH_SIZE:
|
case GL_TEXTURE_DEPTH_SIZE:
|
||||||
case GL_TEXTURE_STENCIL_SIZE:
|
case GL_TEXTURE_STENCIL_SIZE:
|
||||||
|
case GL_TEXTURE_SHARED_SIZE:
|
||||||
if (params) {
|
if (params) {
|
||||||
*params = static_cast<GLfloat>(GetTextureLevelComponentParameter(textureObject->GetFormat(), pname));
|
*params = static_cast<GLfloat>(GetTextureLevelComponentParameter(textureObject->GetFormat(), pname));
|
||||||
}
|
}
|
||||||
@@ -3644,9 +3652,54 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Bool ValidateCopyTextureSubImage(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject, GLint level,
|
||||||
|
GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height,
|
||||||
|
GLsizei depth, const char* caller);
|
||||||
|
|
||||||
|
// The shared body of glCopyTexSubImage3D and glCopyTextureSubImage3D once the caller has
|
||||||
|
// resolved the destination texture. `allowCubeFaceFromZOffset` is the ONE difference between
|
||||||
|
// the two forms: the DSA form takes a cube map and selects the face with zoffset (GL 4.6 core
|
||||||
|
// 8.6), while the target-taking form cannot even name a cube map here - GL_TEXTURE_CUBE_MAP is
|
||||||
|
// not in glCopyTexSubImage3D's accepted-target list, its faces go through
|
||||||
|
// glCopyTexSubImage2D - so for it zoffset is always a layer index.
|
||||||
|
static void CopyTextureSubImage3DResolved(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
|
||||||
|
GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x,
|
||||||
|
GLint y, GLsizei width, GLsizei height, Bool allowCubeFaceFromZOffset,
|
||||||
|
const char* caller) {
|
||||||
|
if (!ValidateCopyTextureSubImage(textureObject, level, xoffset, yoffset, zoffset, width, height, 1, caller)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TextureUploadTarget uploadTarget = GetPrimaryUploadTarget(textureObject);
|
||||||
|
GLint sliceOffset = zoffset;
|
||||||
|
if (allowCubeFaceFromZOffset && textureObject->GetTarget() == TextureTarget::TextureCubeMap) {
|
||||||
|
uploadTarget = static_cast<TextureUploadTarget>(
|
||||||
|
static_cast<SizeT>(TextureUploadTarget::CubeMapPositiveX) + static_cast<SizeT>(zoffset));
|
||||||
|
sliceOffset = 0;
|
||||||
|
}
|
||||||
|
CopyReadFramebufferIntoMipmapRegion(textureObject, uploadTarget, level, xoffset, yoffset, sliceOffset, x, y,
|
||||||
|
width, height, caller);
|
||||||
|
}
|
||||||
|
|
||||||
void CopyTexSubImage3D_State(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x,
|
void CopyTexSubImage3D_State(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x,
|
||||||
GLint y, GLsizei width, GLsizei height) {
|
GLint y, GLsizei width, GLsizei height) {
|
||||||
// TODO: implement
|
// GL 4.6 core 8.6 table: the three-dimensional form of the bound-texture copy accepts
|
||||||
|
// exactly TEXTURE_3D, TEXTURE_2D_ARRAY and TEXTURE_CUBE_MAP_ARRAY. A cube map's faces are
|
||||||
|
// two-dimensional targets of their own and go through glCopyTexSubImage2D.
|
||||||
|
const auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
|
||||||
|
if (textureTarget != TextureTarget::Texture3D && textureTarget != TextureTarget::Texture2DArray &&
|
||||||
|
textureTarget != TextureTarget::TextureCubeMapArray) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum,
|
||||||
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||||
|
"glCopyTexSubImage3D requires GL_TEXTURE_3D, GL_TEXTURE_2D_ARRAY or "
|
||||||
|
"GL_TEXTURE_CUBE_MAP_ARRAY."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
|
||||||
|
auto& textureObject = GetTextureObjectByTarget(textureUploadTarget, textureTarget);
|
||||||
|
if (!textureObject) return;
|
||||||
|
CopyTextureSubImage3DResolved(textureObject, level, xoffset, yoffset, zoffset, x, y, width, height,
|
||||||
|
/*allowCubeFaceFromZOffset=*/false, __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
// What the three CopyTextureSubImage forms check in common (GL 4.6 core 8.6), once the caller
|
// What the three CopyTextureSubImage forms check in common (GL 4.6 core 8.6), once the caller
|
||||||
@@ -4012,7 +4065,22 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CopyTexSubImage1D_State(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) {
|
void CopyTexSubImage1D_State(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) {
|
||||||
// TODO: implement
|
// The bound-texture form of glCopyTextureSubImage1D. GL 4.6 core 8.6 accepts only
|
||||||
|
// GL_TEXTURE_1D here.
|
||||||
|
const auto textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
|
||||||
|
if (textureTarget != TextureTarget::Texture1D) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum,
|
||||||
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||||
|
"glCopyTexSubImage1D requires GL_TEXTURE_1D."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto textureUploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target);
|
||||||
|
auto& textureObject = GetTextureObjectByTarget(textureUploadTarget, textureTarget);
|
||||||
|
if (!textureObject) return;
|
||||||
|
if (!ValidateCopyTextureSubImage(textureObject, level, xoffset, 0, 0, width, 1, 1, __func__)) return;
|
||||||
|
CopyReadFramebufferIntoMipmapRegion(textureObject, GetPrimaryUploadTarget(textureObject), level, xoffset,
|
||||||
|
/*yoffset=*/0, /*zoffset=*/0, x, y, width, /*height=*/1, __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bool CopyTexImage2D_State(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
|
Bool CopyTexImage2D_State(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width,
|
||||||
@@ -4468,6 +4536,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return;
|
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return;
|
||||||
if (!TextureImpl::ValidateTextureLevelNumber(level)) return;
|
if (!TextureImpl::ValidateTextureLevelNumber(level)) return;
|
||||||
if (!TextureImpl::ValidateTextureSizeWithTextureUploadTarget(textureUploadTarget, width, height)) return;
|
if (!TextureImpl::ValidateTextureSizeWithTextureUploadTarget(textureUploadTarget, width, height)) return;
|
||||||
|
if (!TextureImpl::ValidateCubeMapArrayShape(textureUploadTarget, width, height, depth, __func__)) return;
|
||||||
if (!TextureImpl::ValidateTextureSizeRange(width, height, depth)) return;
|
if (!TextureImpl::ValidateTextureSizeRange(width, height, depth)) return;
|
||||||
if (!TextureImpl::ValidateTextureBorderNumber(border)) return;
|
if (!TextureImpl::ValidateTextureBorderNumber(border)) return;
|
||||||
if (!TextureImpl::ValidateTextureLevelWithUploadTarget(textureUploadTarget, level)) return;
|
if (!TextureImpl::ValidateTextureLevelWithUploadTarget(textureUploadTarget, level)) return;
|
||||||
@@ -5206,17 +5275,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!ValidateTextureMutable(textureObject, __func__)) return;
|
if (!ValidateTextureMutable(textureObject, __func__)) return;
|
||||||
if (textureObject->GetTarget() == TextureTarget::TextureCubeMapArray &&
|
|
||||||
(width != height || depth % 6 != 0)) {
|
|
||||||
MG_State::pGLContext->RecordError(
|
|
||||||
ErrorCode::InvalidValue,
|
|
||||||
MakeUnique<GenericErrorInfo>(
|
|
||||||
"MG_Impl/GLImpl", __func__,
|
|
||||||
"Cube map array immutable storage must be square with depth multiple of 6."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto textureUploadTarget = GetPrimaryUploadTarget(textureObject);
|
const auto textureUploadTarget = GetPrimaryUploadTarget(textureObject);
|
||||||
|
// The cube-array shape rules, shared with glTexImage3D / glCompressedTexImage3D so the
|
||||||
|
// three cannot drift (they had: this check used to exist here and nowhere else).
|
||||||
|
if (!TextureImpl::ValidateCubeMapArrayShape(textureUploadTarget, width, height, depth, __func__)) return;
|
||||||
|
|
||||||
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return;
|
if (!TextureImpl::ValidateTextureUploadTarget(textureUploadTarget)) return;
|
||||||
auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
|
auto* textureMipmapObject = static_cast<MG_State::GLState::TextureObjectMipmap*>(textureObject.get());
|
||||||
|
|
||||||
@@ -6649,20 +6712,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
"cube map array texture."));
|
"cube map array texture."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!ValidateCopyTextureSubImage(textureObject, level, xoffset, yoffset, zoffset, width, height, 1, __func__)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// A cube map addresses its faces as separate upload targets, so zoffset selects the target
|
// A cube map addresses its faces as separate upload targets, so zoffset selects the target
|
||||||
// rather than a slice within one; every other layered target keeps zoffset as the slice.
|
// rather than a slice within one; every other layered target keeps zoffset as the slice.
|
||||||
TextureUploadTarget uploadTarget = GetPrimaryUploadTarget(textureObject);
|
CopyTextureSubImage3DResolved(textureObject, level, xoffset, yoffset, zoffset, x, y, width, height,
|
||||||
GLint sliceOffset = zoffset;
|
/*allowCubeFaceFromZOffset=*/true, __func__);
|
||||||
if (target == TextureTarget::TextureCubeMap) {
|
|
||||||
uploadTarget = static_cast<TextureUploadTarget>(
|
|
||||||
static_cast<SizeT>(TextureUploadTarget::CubeMapPositiveX) + static_cast<SizeT>(zoffset));
|
|
||||||
sliceOffset = 0;
|
|
||||||
}
|
|
||||||
CopyReadFramebufferIntoMipmapRegion(textureObject, uploadTarget, level, xoffset, yoffset, sliceOffset, x, y,
|
|
||||||
width, height, __func__);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) {
|
void CopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) {
|
||||||
|
|||||||
@@ -103,6 +103,28 @@ namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Bool ValidateCubeMapArrayShape(TextureUploadTarget target, GLsizei width, GLsizei height, GLsizei depth,
|
||||||
|
const char* caller) {
|
||||||
|
if (target != TextureUploadTarget::CubeMapArray && target != TextureUploadTarget::ProxyCubeMapArray) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (width != height) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||||
|
"Cube map array levels must be square (width == height)"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (depth % 6 != 0) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||||
|
"Cube map array depth must be a multiple of six"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Bool ValidateTextureSizeWithTextureUploadTarget(TextureUploadTarget target, GLsizei width, GLsizei height) {
|
Bool ValidateTextureSizeWithTextureUploadTarget(TextureUploadTarget target, GLsizei width, GLsizei height) {
|
||||||
if (target == TextureUploadTarget::CubeMapPositiveX || target == TextureUploadTarget::CubeMapNegativeX ||
|
if (target == TextureUploadTarget::CubeMapPositiveX || target == TextureUploadTarget::CubeMapNegativeX ||
|
||||||
target == TextureUploadTarget::CubeMapPositiveY || target == TextureUploadTarget::CubeMapNegativeY ||
|
target == TextureUploadTarget::CubeMapPositiveY || target == TextureUploadTarget::CubeMapNegativeY ||
|
||||||
|
|||||||
@@ -20,6 +20,13 @@ namespace MobileGL::MG_Impl::GLImpl::TextureImpl {
|
|||||||
Bool ValidateTexturePixelDataType(TexturePixelDataType texturePixelDataType);
|
Bool ValidateTexturePixelDataType(TexturePixelDataType texturePixelDataType);
|
||||||
Bool ValidateTextureLevelNumber(Int level);
|
Bool ValidateTextureLevelNumber(Int level);
|
||||||
Bool ValidateTextureSizeWithTextureUploadTarget(TextureUploadTarget target, GLsizei width, GLsizei height);
|
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 ValidateTextureSizeRange(Int width, Int height, Int depth);
|
||||||
Bool ValidateTextureInternalFormat(TextureInternalFormat format);
|
Bool ValidateTextureInternalFormat(TextureInternalFormat format);
|
||||||
Bool ValidateTextureBorderNumber(Int border);
|
Bool ValidateTextureBorderNumber(Int border);
|
||||||
|
|||||||
@@ -5545,3 +5545,155 @@ TEST_F(TextureTest, ImageWidenedUploadSplitsAPacked2101010RevShadowIntoFourChann
|
|||||||
EXPECT_TRUE(empty.empty());
|
EXPECT_TRUE(empty.empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
// GL_TEXTURE_CUBE_MAP_ARRAY: the shape rules, the shared-exponent level query, and the
|
||||||
|
// three-dimensional bound-texture copy. All three were front-end gaps rather than backend ones -
|
||||||
|
// the DirectVulkan baseline failed the identical conformance bodies.
|
||||||
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// glTexStorage3D carried the two cube-array shape rules inline and glTexImage3D carried neither,
|
||||||
|
// which is exactly why esextcTextureCubeMapArrayTex3DValidation failed on its two glTexImage3D
|
||||||
|
// assertions and passed both glTexStorage3D ones. The predicate now lives in one validator that
|
||||||
|
// every level-defining entry point calls.
|
||||||
|
TEST_F(TextureTest, TexImage3DAppliesTheCubeMapArrayShapeRules) {
|
||||||
|
GLuint texture = 0;
|
||||||
|
MG_Impl::GLImpl::GenTextures(1, &texture);
|
||||||
|
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, texture);
|
||||||
|
DrainPendingGlErrors();
|
||||||
|
|
||||||
|
// Non-square faces are GL_INVALID_VALUE.
|
||||||
|
MG_Impl::GLImpl::TexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, GL_RGBA8, 4, 8, 6, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||||
|
nullptr);
|
||||||
|
ExpectSingleGlError(GL_INVALID_VALUE);
|
||||||
|
|
||||||
|
// A depth that is not a whole number of cubes is GL_INVALID_VALUE.
|
||||||
|
MG_Impl::GLImpl::TexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, GL_RGBA8, 4, 4, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||||
|
nullptr);
|
||||||
|
ExpectSingleGlError(GL_INVALID_VALUE);
|
||||||
|
|
||||||
|
// The legal shape still goes through untouched.
|
||||||
|
MG_Impl::GLImpl::TexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, GL_RGBA8, 4, 4, 12, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||||
|
nullptr);
|
||||||
|
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||||
|
|
||||||
|
// And the rules are not applied to targets they do not belong to: a 2D array may be any
|
||||||
|
// rectangle with any layer count.
|
||||||
|
GLuint arrayTexture = 0;
|
||||||
|
MG_Impl::GLImpl::GenTextures(1, &arrayTexture);
|
||||||
|
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D_ARRAY, arrayTexture);
|
||||||
|
MG_Impl::GLImpl::TexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4, 8, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||||
|
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||||
|
|
||||||
|
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D_ARRAY, 0);
|
||||||
|
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TextureTest, TexStorage3DKeepsTheCubeMapArrayShapeRulesAfterTheyMovedIntoTheSharedValidator) {
|
||||||
|
GLuint texture = 0;
|
||||||
|
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_CUBE_MAP_ARRAY, 1, &texture);
|
||||||
|
DrainPendingGlErrors();
|
||||||
|
|
||||||
|
MG_Impl::GLImpl::TextureStorage3D(texture, 1, GL_RGBA8, 4, 8, 6);
|
||||||
|
ExpectSingleGlError(GL_INVALID_VALUE);
|
||||||
|
|
||||||
|
GLuint second = 0;
|
||||||
|
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_CUBE_MAP_ARRAY, 1, &second);
|
||||||
|
MG_Impl::GLImpl::TextureStorage3D(second, 1, GL_RGBA8, 4, 4, 5);
|
||||||
|
ExpectSingleGlError(GL_INVALID_VALUE);
|
||||||
|
|
||||||
|
GLuint third = 0;
|
||||||
|
MG_Impl::GLImpl::CreateTextures(GL_TEXTURE_CUBE_MAP_ARRAY, 1, &third);
|
||||||
|
MG_Impl::GLImpl::TextureStorage3D(third, 1, GL_RGBA8, 4, 4, 6);
|
||||||
|
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GL_TEXTURE_SHARED_SIZE (0x8C3F) had no case in either glGetTexLevelParameter switch, so it fell
|
||||||
|
// into the terminal default arm and raised GL_INVALID_ENUM. esextcTextureCubeMapArrayGetterCalls
|
||||||
|
// walks a fixed pname list and TCU_FAILs on the first error, so the whole body died there even
|
||||||
|
// though every other pname it asks for was already implemented.
|
||||||
|
TEST_F(TextureTest, GetTexLevelParameterAnswersSharedSize) {
|
||||||
|
GLuint texture = 0;
|
||||||
|
MG_Impl::GLImpl::GenTextures(1, &texture);
|
||||||
|
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, texture);
|
||||||
|
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||||
|
DrainPendingGlErrors();
|
||||||
|
|
||||||
|
GLint sharedSize = -1;
|
||||||
|
MG_Impl::GLImpl::GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_SHARED_SIZE, &sharedSize);
|
||||||
|
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||||
|
EXPECT_EQ(sharedSize, 0) << "only a shared-exponent format has a shared exponent";
|
||||||
|
|
||||||
|
GLfloat sharedSizeF = -1.0f;
|
||||||
|
MG_Impl::GLImpl::GetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_SHARED_SIZE, &sharedSizeF);
|
||||||
|
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||||
|
EXPECT_FLOAT_EQ(sharedSizeF, 0.0f) << "the fv switch is a copy of the iv one and must not drift";
|
||||||
|
|
||||||
|
// RGB9_E5 is the one format that HAS one, and it is five bits wide.
|
||||||
|
GLuint sharedTexture = 0;
|
||||||
|
MG_Impl::GLImpl::GenTextures(1, &sharedTexture);
|
||||||
|
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, sharedTexture);
|
||||||
|
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGB9_E5, 4, 4, 0, GL_RGB, GL_FLOAT, nullptr);
|
||||||
|
DrainPendingGlErrors();
|
||||||
|
|
||||||
|
sharedSize = -1;
|
||||||
|
MG_Impl::GLImpl::GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_SHARED_SIZE, &sharedSize);
|
||||||
|
EXPECT_EQ(MG_Impl::GLImpl::GetError(), GL_NO_ERROR);
|
||||||
|
EXPECT_EQ(sharedSize, 5);
|
||||||
|
|
||||||
|
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// glCopyTexSubImage3D was `{ // TODO: implement }` - no validation, no error, no copy - while its
|
||||||
|
// DSA sibling was fully implemented right next door. The two now share one body, so the target
|
||||||
|
// rules are the only thing that separates them.
|
||||||
|
TEST_F(TextureTest, CopyTexSubImage3DRejectsTargetsTheThreeDimensionalFormDoesNotTake) {
|
||||||
|
GLuint texture = 0;
|
||||||
|
MG_Impl::GLImpl::GenTextures(1, &texture);
|
||||||
|
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, texture);
|
||||||
|
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||||
|
DrainPendingGlErrors();
|
||||||
|
|
||||||
|
// GL 4.6 core 8.6: the 3D form takes only TEXTURE_3D / TEXTURE_2D_ARRAY /
|
||||||
|
// TEXTURE_CUBE_MAP_ARRAY. A cube map's faces are two-dimensional targets and go through
|
||||||
|
// glCopyTexSubImage2D. This used to be accepted silently, which is how the defect hid.
|
||||||
|
MG_Impl::GLImpl::CopyTexSubImage3D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 0, 2, 2);
|
||||||
|
ExpectSingleGlError(GL_INVALID_ENUM);
|
||||||
|
MG_Impl::GLImpl::CopyTexSubImage3D(GL_TEXTURE_CUBE_MAP, 0, 0, 0, 0, 0, 0, 2, 2);
|
||||||
|
ExpectSingleGlError(GL_INVALID_ENUM);
|
||||||
|
|
||||||
|
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TextureTest, CopyTexSubImage3DValidatesTheDestinationRegionOnACubeMapArray) {
|
||||||
|
GLuint texture = 0;
|
||||||
|
MG_Impl::GLImpl::GenTextures(1, &texture);
|
||||||
|
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, texture);
|
||||||
|
MG_Impl::GLImpl::TexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, GL_RGBA8, 4, 4, 6, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||||
|
nullptr);
|
||||||
|
DrainPendingGlErrors();
|
||||||
|
|
||||||
|
// A negative level is GL_INVALID_VALUE, and reaching it at all proves the entry point now
|
||||||
|
// validates instead of returning silently.
|
||||||
|
MG_Impl::GLImpl::CopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, -1, 0, 0, 0, 0, 0, 2, 2);
|
||||||
|
ExpectSingleGlError(GL_INVALID_VALUE);
|
||||||
|
|
||||||
|
// So is a negative extent.
|
||||||
|
MG_Impl::GLImpl::CopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, 0, 0, 0, 0, 0, -2, 2);
|
||||||
|
ExpectSingleGlError(GL_INVALID_VALUE);
|
||||||
|
|
||||||
|
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TextureTest, CopyTexSubImage1DRejectsAnythingButTexture1D) {
|
||||||
|
GLuint texture = 0;
|
||||||
|
MG_Impl::GLImpl::GenTextures(1, &texture);
|
||||||
|
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, texture);
|
||||||
|
MG_Impl::GLImpl::TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||||
|
DrainPendingGlErrors();
|
||||||
|
|
||||||
|
MG_Impl::GLImpl::CopyTexSubImage1D(GL_TEXTURE_2D, 0, 0, 0, 0, 2);
|
||||||
|
ExpectSingleGlError(GL_INVALID_ENUM);
|
||||||
|
|
||||||
|
MG_Impl::GLImpl::BindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user