| // |
| // Copyright 2023 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. |
| // |
| // Test state requests and compilation of tokens added by OES_shader_multisample_interpolation |
| |
| #include "common/mathutil.h" |
| #include "test_utils/ANGLETest.h" |
| #include "test_utils/gl_raii.h" |
| |
| using namespace angle; |
| |
| namespace |
| { |
| |
| class SampleMultisampleInterpolationTest : public ANGLETest<> |
| { |
| protected: |
| SampleMultisampleInterpolationTest() |
| { |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| setConfigAlphaBits(8); |
| setExtensionsEnabled(false); |
| } |
| }; |
| |
| // Test state queries |
| TEST_P(SampleMultisampleInterpolationTest, StateQueries) |
| { |
| // New state queries fail without the extension |
| { |
| GLint bits = 0; |
| glGetIntegerv(GL_FRAGMENT_INTERPOLATION_OFFSET_BITS_OES, &bits); |
| EXPECT_GL_ERROR(GL_INVALID_ENUM); |
| EXPECT_EQ(bits, 0); |
| |
| GLfloat minOffset = 0.0f; |
| glGetFloatv(GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_OES, &minOffset); |
| EXPECT_GL_ERROR(GL_INVALID_ENUM); |
| EXPECT_EQ(minOffset, 0.0f); |
| |
| GLfloat maxOffset = 0.0f; |
| glGetFloatv(GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_OES, &maxOffset); |
| EXPECT_GL_ERROR(GL_INVALID_ENUM); |
| EXPECT_EQ(maxOffset, 0.0f); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_shader_multisample_interpolation")); |
| |
| // Implementation-dependent values |
| { |
| GLint bits = 0; |
| glGetIntegerv(GL_FRAGMENT_INTERPOLATION_OFFSET_BITS_OES, &bits); |
| EXPECT_GE(bits, 4); |
| |
| GLfloat minOffset = 0.0f; |
| glGetFloatv(GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_OES, &minOffset); |
| EXPECT_LE(minOffset, -0.5f); |
| |
| GLfloat maxOffset = 0.0f; |
| glGetFloatv(GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_OES, &maxOffset); |
| EXPECT_GE(maxOffset, 0.5f - std::pow(2, -bits)); |
| |
| ASSERT_GL_NO_ERROR(); |
| } |
| } |
| |
| // Test gl_SampleMaskIn values with per-sample shading |
| TEST_P(SampleMultisampleInterpolationTest, SampleMaskInPerSample) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_sample_variables")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_shader_multisample_interpolation")); |
| |
| const char kVS[] = R"(#version 300 es |
| #extension GL_OES_shader_multisample_interpolation : require |
| |
| in vec4 a_position; |
| sample out float interpolant; |
| |
| void main() |
| { |
| gl_Position = a_position; |
| interpolant = 0.5; |
| })"; |
| |
| const char kFS[] = R"(#version 300 es |
| #extension GL_OES_sample_variables : require |
| #extension GL_OES_shader_multisample_interpolation : require |
| |
| precision highp float; |
| sample in float interpolant; |
| out vec4 color; |
| |
| bool isPow2(int v) |
| { |
| return v != 0 && (v & (v - 1)) == 0; |
| } |
| |
| void main() |
| { |
| float r = float(isPow2(gl_SampleMaskIn[0])); |
| color = vec4(r, interpolant, 0, 1); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, kVS, kFS); |
| glUseProgram(program); |
| |
| for (GLint sampleCount : {0, 4}) |
| { |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| GLRenderbuffer rbo; |
| glBindRenderbuffer(GL_RENDERBUFFER, rbo); |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_RGBA8, 1, 1); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); |
| drawQuad(program, "a_position", 0.0); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| GLubyte pixel[4]; |
| glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_EQ(pixel[0], 255) << "Samples: " << sampleCount; |
| } |
| } |
| |
| // Test gl_SampleMaskIn values with per-sample noperspective shading |
| TEST_P(SampleMultisampleInterpolationTest, SampleMaskInPerSampleNoPerspective) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_sample_variables")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_shader_multisample_interpolation")); |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_NV_shader_noperspective_interpolation")); |
| |
| const char kVS[] = R"(#version 300 es |
| #extension GL_OES_shader_multisample_interpolation : require |
| #extension GL_NV_shader_noperspective_interpolation : require |
| |
| in vec4 a_position; |
| noperspective sample out float interpolant; |
| |
| void main() |
| { |
| gl_Position = a_position; |
| interpolant = 0.5; |
| })"; |
| |
| const char kFS[] = R"(#version 300 es |
| #extension GL_OES_sample_variables : require |
| #extension GL_OES_shader_multisample_interpolation : require |
| #extension GL_NV_shader_noperspective_interpolation : require |
| |
| precision highp float; |
| noperspective sample in float interpolant; |
| out vec4 color; |
| |
| bool isPow2(int v) |
| { |
| return v != 0 && (v & (v - 1)) == 0; |
| } |
| |
| void main() |
| { |
| float r = float(isPow2(gl_SampleMaskIn[0])); |
| color = vec4(r, interpolant, 0, 1); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, kVS, kFS); |
| glUseProgram(program); |
| |
| for (GLint sampleCount : {0, 4}) |
| { |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| GLRenderbuffer rbo; |
| glBindRenderbuffer(GL_RENDERBUFFER, rbo); |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_RGBA8, 1, 1); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); |
| drawQuad(program, "a_position", 0.0); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| GLubyte pixel[4]; |
| glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel); |
| ASSERT_GL_NO_ERROR(); |
| |
| EXPECT_EQ(pixel[0], 255) << "Samples: " << sampleCount; |
| } |
| } |
| |
| // Test that a shader with interpolateAt* calls and directly used interpolants compiles |
| // successfully. |
| TEST_P(SampleMultisampleInterpolationTest, CompileInterpolateAt) |
| { |
| ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_OES_shader_multisample_interpolation")); |
| |
| EnsureGLExtensionEnabled("GL_NV_shader_noperspective_interpolation"); |
| |
| constexpr char kVS[] = R"(#version 300 es |
| #extension GL_OES_shader_multisample_interpolation : require |
| #extension GL_NV_shader_noperspective_interpolation : enable |
| |
| precision highp float; |
| |
| out float interpolant; |
| out float interpolantArray[2]; |
| |
| centroid out float interpolantCentroid; |
| centroid out float interpolantCentroidArray[2]; |
| |
| sample out float interpolantSample; |
| sample out float interpolantSampleArray[2]; |
| |
| smooth out float interpolantSmooth; |
| smooth out float interpolantSmoothArray[2]; |
| |
| flat out float interpolantFlat; |
| flat out float interpolantFlatArray[2]; |
| |
| #ifdef GL_NV_shader_noperspective_interpolation |
| noperspective out float interpolantNp; |
| noperspective out float interpolantNpArray[2]; |
| |
| noperspective centroid out float interpolantNpCentroid; |
| noperspective centroid out float interpolantNpCentroidArray[2]; |
| |
| noperspective sample out float interpolantNpSample; |
| noperspective sample out float interpolantNpSampleArray[2]; |
| #endif |
| |
| void main() |
| { |
| gl_Position = vec4(0, 0, 0, 1); |
| |
| interpolant = 1.0; |
| interpolantArray[1] = 2.0; |
| |
| interpolantCentroid = 3.0; |
| interpolantCentroidArray[1] = 4.0; |
| |
| interpolantSample = 5.0; |
| interpolantSampleArray[1] = 6.0; |
| |
| interpolantSmooth = 7.0; |
| interpolantSmoothArray[1] = 8.0; |
| |
| interpolantFlat = 9.0; |
| interpolantFlatArray[1] = 10.0; |
| |
| #ifdef GL_NV_shader_noperspective_interpolation |
| interpolantNp = 11.0; |
| interpolantNpArray[1] = 12.0; |
| |
| interpolantNpCentroid = 13.0; |
| interpolantNpCentroidArray[1] = 14.0; |
| |
| interpolantNpSample = 15.0; |
| interpolantNpSampleArray[1] = 16.0; |
| #endif |
| })"; |
| |
| constexpr char kFS[] = R"(#version 300 es |
| #extension GL_OES_shader_multisample_interpolation : require |
| #extension GL_NV_shader_noperspective_interpolation : enable |
| |
| precision highp float; |
| |
| in float interpolant; |
| in float interpolantArray[2]; |
| |
| centroid in float interpolantCentroid; |
| centroid in float interpolantCentroidArray[2]; |
| |
| sample in float interpolantSample; |
| sample in float interpolantSampleArray[2]; |
| |
| smooth in float interpolantSmooth; |
| smooth in float interpolantSmoothArray[2]; |
| |
| flat in float interpolantFlat; |
| flat in float interpolantFlatArray[2]; |
| |
| #ifdef GL_NV_shader_noperspective_interpolation |
| noperspective in float interpolantNp; |
| noperspective in float interpolantNpArray[2]; |
| |
| noperspective centroid in float interpolantNpCentroid; |
| noperspective centroid in float interpolantNpCentroidArray[2]; |
| |
| noperspective sample in float interpolantNpSample; |
| noperspective sample in float interpolantNpSampleArray[2]; |
| #endif |
| |
| out vec4 color; |
| |
| void main() |
| { |
| float r; |
| |
| r += interpolateAtCentroid(interpolant); |
| r += interpolateAtSample(interpolant, int(interpolant)); |
| r += interpolateAtOffset(interpolant, vec2(interpolant)); |
| |
| r += interpolateAtCentroid(interpolantArray[1]); |
| r += interpolateAtSample(interpolantArray[1], int(interpolantArray[0])); |
| r += interpolateAtOffset(interpolantArray[1], vec2(interpolantArray[0])); |
| |
| r += interpolateAtCentroid(interpolantCentroid); |
| r += interpolateAtSample(interpolantCentroid, int(interpolantCentroid)); |
| r += interpolateAtOffset(interpolantCentroid, vec2(interpolantCentroid)); |
| |
| r += interpolateAtCentroid(interpolantCentroidArray[1]); |
| r += interpolateAtSample(interpolantCentroidArray[1], int(interpolantCentroidArray[0])); |
| r += interpolateAtOffset(interpolantCentroidArray[1], vec2(interpolantCentroidArray[0])); |
| |
| r += interpolateAtCentroid(interpolantSample); |
| r += interpolateAtSample(interpolantSample, int(interpolantSample)); |
| r += interpolateAtOffset(interpolantSample, vec2(interpolantSample)); |
| |
| r += interpolateAtCentroid(interpolantSampleArray[1]); |
| r += interpolateAtSample(interpolantSampleArray[1], int(interpolantSampleArray[0])); |
| r += interpolateAtOffset(interpolantSampleArray[1], vec2(interpolantSampleArray[0])); |
| |
| r += interpolateAtCentroid(interpolantSmooth); |
| r += interpolateAtSample(interpolantSmooth, int(interpolantSmooth)); |
| r += interpolateAtOffset(interpolantSmooth, vec2(interpolantSmooth)); |
| |
| r += interpolateAtCentroid(interpolantSmoothArray[1]); |
| r += interpolateAtSample(interpolantSmoothArray[1], int(interpolantSmoothArray[0])); |
| r += interpolateAtOffset(interpolantSmoothArray[1], vec2(interpolantSmoothArray[0])); |
| |
| r += interpolateAtCentroid(interpolantFlat); |
| r += interpolateAtSample(interpolantFlat, int(interpolantFlat)); |
| r += interpolateAtOffset(interpolantFlat, vec2(interpolantFlat)); |
| |
| r += interpolateAtCentroid(interpolantFlatArray[1]); |
| r += interpolateAtSample(interpolantFlatArray[1], int(interpolantFlatArray[0])); |
| r += interpolateAtOffset(interpolantFlatArray[1], vec2(interpolantFlatArray[0])); |
| |
| #ifdef GL_NV_shader_noperspective_interpolation |
| r += interpolateAtCentroid(interpolantNp); |
| r += interpolateAtSample(interpolantNp, int(interpolantNp)); |
| r += interpolateAtOffset(interpolantNp, vec2(interpolantNp)); |
| |
| r += interpolateAtCentroid(interpolantNpArray[1]); |
| r += interpolateAtSample(interpolantNpArray[1], int(interpolantNpArray[0])); |
| r += interpolateAtOffset(interpolantNpArray[1], vec2(interpolantNpArray[0])); |
| |
| r += interpolateAtCentroid(interpolantNpCentroid); |
| r += interpolateAtSample(interpolantNpCentroid, int(interpolantNpCentroid)); |
| r += interpolateAtOffset(interpolantNpCentroid, vec2(interpolantNpCentroid)); |
| |
| r += interpolateAtCentroid(interpolantNpCentroidArray[1]); |
| r += interpolateAtSample(interpolantNpCentroidArray[1], int(interpolantNpCentroidArray[0])); |
| r += interpolateAtOffset(interpolantNpCentroidArray[1], vec2(interpolantNpCentroidArray[0])); |
| |
| r += interpolateAtCentroid(interpolantNpSample); |
| r += interpolateAtSample(interpolantNpSample, int(interpolantNpSample)); |
| r += interpolateAtOffset(interpolantNpSample, vec2(interpolantNpSample)); |
| |
| r += interpolateAtCentroid(interpolantNpSampleArray[1]); |
| r += interpolateAtSample(interpolantNpSampleArray[1], int(interpolantNpSampleArray[0])); |
| r += interpolateAtOffset(interpolantNpSampleArray[1], vec2(interpolantNpSampleArray[0])); |
| #endif |
| |
| color = vec4(r); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, kVS, kFS); |
| } |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SampleMultisampleInterpolationTest); |
| ANGLE_INSTANTIATE_TEST_ES3(SampleMultisampleInterpolationTest); |
| |
| } // anonymous namespace |