| // |
| // Copyright 2026 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| // QCOMTextureLodBiasTest.cpp: |
| // Tests for the GL_QCOM_texture_lod_bias extension. |
| |
| #include "test_utils/ANGLETest.h" |
| #include "test_utils/gl_raii.h" |
| |
| using namespace angle; |
| |
| class QCOMTextureLodBiasTest : public ANGLETest<> |
| { |
| protected: |
| QCOMTextureLodBiasTest() |
| { |
| setWindowWidth(32); |
| setWindowHeight(32); |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| setConfigAlphaBits(8); |
| } |
| |
| void testSetUp() override |
| { |
| mProgram = CompileProgram(essl1_shaders::vs::Texture2D(), essl1_shaders::fs::Texture2D()); |
| if (mProgram == 0) |
| { |
| FAIL() << "shader compilation failed"; |
| } |
| } |
| |
| void testTearDown() override |
| { |
| if (mProgram != 0) |
| { |
| glDeleteProgram(mProgram); |
| } |
| } |
| |
| void createMipmappedTexture() |
| { |
| // Level 0: Red |
| std::vector<GLColor> redColor(4 * 4, GLColor::red); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| redColor.data()); |
| |
| // Level 1: Green |
| std::vector<GLColor> greenColor(2 * 2, GLColor::green); |
| glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| greenColor.data()); |
| |
| // Level 2: Blue |
| std::vector<GLColor> blueColor(1 * 1, GLColor::blue); |
| glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, |
| blueColor.data()); |
| } |
| |
| GLuint mProgram = 0; |
| }; |
| |
| // Test that GL_TEXTURE_LOD_BIAS_QCOM can be set and queried. |
| TEST_P(QCOMTextureLodBiasTest, Query) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_QCOM_texture_lod_bias")); |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| |
| // Default value should be 0.0 |
| GLfloat bias = -1.0f; |
| glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS_QCOM, &bias); |
| EXPECT_GL_NO_ERROR(); |
| EXPECT_EQ(0.0f, bias); |
| |
| // Set a positive bias |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS_QCOM, 1.5f); |
| EXPECT_GL_NO_ERROR(); |
| |
| glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS_QCOM, &bias); |
| EXPECT_GL_NO_ERROR(); |
| EXPECT_EQ(1.5f, bias); |
| |
| // Set a negative bias |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS_QCOM, -1.5f); |
| EXPECT_GL_NO_ERROR(); |
| |
| glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS_QCOM, &bias); |
| EXPECT_GL_NO_ERROR(); |
| EXPECT_EQ(-1.5f, bias); |
| } |
| |
| // Test that GL_TEXTURE_LOD_BIAS_QCOM can be set and queried on sampler objects. |
| TEST_P(QCOMTextureLodBiasTest, SamplerQuery) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_QCOM_texture_lod_bias")); |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); |
| |
| GLSampler sampler; |
| |
| // Default value should be 0.0 |
| GLfloat bias = -1.0f; |
| glGetSamplerParameterfv(sampler, GL_TEXTURE_LOD_BIAS_QCOM, &bias); |
| EXPECT_GL_NO_ERROR(); |
| EXPECT_EQ(0.0f, bias); |
| |
| glSamplerParameterf(sampler, GL_TEXTURE_LOD_BIAS_QCOM, 1.5f); |
| EXPECT_GL_NO_ERROR(); |
| |
| glGetSamplerParameterfv(sampler, GL_TEXTURE_LOD_BIAS_QCOM, &bias); |
| EXPECT_GL_NO_ERROR(); |
| EXPECT_EQ(1.5f, bias); |
| } |
| |
| // Test that GL_TEXTURE_LOD_BIAS_QCOM affects rendering. |
| TEST_P(QCOMTextureLodBiasTest, Render) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_QCOM_texture_lod_bias")); |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| |
| createMipmappedTexture(); |
| |
| // Set filtering to LinearMipmapNearest to pick a single mip level |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| |
| // Draw quad that covers the whole viewport (4x4) |
| // It should sample Level 0 (Red) initially |
| glUseProgram(mProgram); |
| glViewport(0, 0, 4, 4); |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Add +1.0 bias. It should sample Level 1 (Green) |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS_QCOM, 1.0f); |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Add +2.0 bias. It should sample Level 2 (Blue) |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS_QCOM, 2.0f); |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| } |
| |
| // Test that GL_TEXTURE_LOD_BIAS_QCOM on sampler objects affects rendering. |
| TEST_P(QCOMTextureLodBiasTest, SamplerRender) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_QCOM_texture_lod_bias")); |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| |
| createMipmappedTexture(); |
| |
| GLSampler sampler; |
| glBindSampler(0, sampler); |
| |
| // Set filtering on sampler |
| glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); |
| glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| |
| // Draw quad that covers the whole viewport (4x4) |
| // It should sample Level 0 (Red) initially |
| glUseProgram(mProgram); |
| glViewport(0, 0, 4, 4); |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| |
| // Add +1.0 bias on sampler. It should sample Level 1 (Green) |
| glSamplerParameterf(sampler, GL_TEXTURE_LOD_BIAS_QCOM, 1.0f); |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Add +2.0 bias on sampler. It should sample Level 2 (Blue) |
| glSamplerParameterf(sampler, GL_TEXTURE_LOD_BIAS_QCOM, 2.0f); |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| |
| glBindSampler(0, 0); |
| } |
| |
| // Test that GL_TEXTURE_LOD_BIAS_QCOM is applied BEFORE TEXTURE_MAX_LOD clamping (Issue 3 in spec). |
| TEST_P(QCOMTextureLodBiasTest, Clamping) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_QCOM_texture_lod_bias")); |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| |
| createMipmappedTexture(); |
| |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| |
| // Set TEXTURE_MAX_LOD to 1.0 (Limit to Level 1) |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 1.0f); |
| |
| // Set bias to 2.0. Base LOD is 0. 0 + 2 = 2. |
| // If applied before clamping: clamp(2, max=1) = 1 (Green). |
| // If applied after clamping: clamp(0, max=1) + 2 = 2 (Blue). |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS_QCOM, 2.0f); |
| |
| glUseProgram(mProgram); |
| glViewport(0, 0, 4, 4); |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| |
| // Expect Green (Level 1) |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| } |
| |
| // According to GL_QCOM_texture_lod_bias spec, the lodBias parameter should be clamped between the |
| // positive and negative values of the implementation defined constant MAX_TEXTURE_LOD_BIAS_EXT. |
| TEST_P(QCOMTextureLodBiasTest, BiasClamping) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_QCOM_texture_lod_bias")); |
| |
| GLfloat maxBias = 0.0f; |
| glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxBias); |
| if (glGetError() != GL_NO_ERROR) |
| { |
| GTEST_SKIP() << "Test skipped: GL_MAX_TEXTURE_LOD_BIAS is not supported"; |
| } |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| |
| createMipmappedTexture(); |
| |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| |
| // Set bias to a value larger than maxBias. |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS_QCOM, maxBias + 1.0f); |
| EXPECT_GL_NO_ERROR(); |
| |
| glUseProgram(mProgram); |
| glViewport(0, 0, 4, 4); |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| |
| // Should still use the max available level (Level 2 - Blue) |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| |
| // Set negative bias larger than -maxBias |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS_QCOM, -(maxBias + 1.0f)); |
| EXPECT_GL_NO_ERROR(); |
| |
| drawQuad(mProgram, essl1_shaders::PositionAttrib(), 0.5f); |
| |
| // Should use the min available level (Level 0 - Red) |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); |
| } |
| |
| // Test that GL_TEXTURE_LOD_BIAS_QCOM affects rendering when using textureLod in shader. |
| TEST_P(QCOMTextureLodBiasTest, RenderWithTextureLod) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_QCOM_texture_lod_bias")); |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); |
| |
| GLTexture texture; |
| glBindTexture(GL_TEXTURE_2D, texture); |
| |
| createMipmappedTexture(); |
| |
| // Set filtering to LinearMipmapNearest to pick a single mip level |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| |
| ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Texture2DLod(), essl3_shaders::fs::Texture2DLod()); |
| glUseProgram(program); |
| |
| GLint texLocation = glGetUniformLocation(program, essl3_shaders::Texture2DUniform()); |
| GLint lodLocation = glGetUniformLocation(program, essl3_shaders::LodUniform()); |
| |
| // Expect texture unit 0 |
| glUniform1i(texLocation, 0); |
| |
| glViewport(0, 0, 4, 4); |
| |
| // Set explicit LOD to 1.0. Base LOD is 0. Total LOD = 1.0. |
| // It should sample Level 1 (Green). |
| glUniform1f(lodLocation, 1.0f); |
| drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| |
| // Add +1.0 bias. Total LOD = 1.0 + 1.0 = 2.0. |
| // It should sample Level 2 (Blue). |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS_QCOM, 1.0f); |
| drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue); |
| |
| // Set explicit LOD to 2.0, and negative bias -1.0. Total LOD = 2.0 - 1.0 = 1.0. |
| // It should sample Level 1 (Green). |
| glUniform1f(lodLocation, 2.0f); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS_QCOM, -1.0f); |
| drawQuad(program, essl3_shaders::PositionAttrib(), 0.5f); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); |
| } |
| |
| ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(QCOMTextureLodBiasTest); |