| // |
| // 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 built-in variables added by OES_sample_variables |
| |
| #include <unordered_set> |
| |
| #include "common/mathutil.h" |
| #include "test_utils/ANGLETest.h" |
| #include "test_utils/gl_raii.h" |
| |
| using namespace angle; |
| |
| namespace |
| { |
| |
| class SampleVariablesTest : public ANGLETest<> |
| { |
| protected: |
| SampleVariablesTest() |
| { |
| setConfigRedBits(8); |
| setConfigGreenBits(8); |
| setConfigBlueBits(8); |
| setConfigAlphaBits(8); |
| } |
| }; |
| |
| // Test gl_MaxSamples == GL_MAX_SAMPLES |
| TEST_P(SampleVariablesTest, MaxSamples) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_sample_variables")); |
| |
| GLint maxSamples = -1; |
| glGetIntegerv(GL_MAX_SAMPLES, &maxSamples); |
| ASSERT_GT(maxSamples, 0); |
| ASSERT_LE(maxSamples, 32); |
| |
| const char kFS[] = R"(#version 300 es |
| #extension GL_OES_sample_variables : require |
| precision highp float; |
| out vec4 color; |
| void main() |
| { |
| color = vec4(float(gl_MaxSamples * 4) / 255.0, 0.0, 0.0, 1.0); |
| })"; |
| |
| ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS); |
| drawQuad(program, essl3_shaders::PositionAttrib(), 0.0); |
| |
| EXPECT_PIXEL_NEAR(0, 0, maxSamples * 4, 0, 0, 255, 1.0); |
| } |
| |
| // Test gl_NumSamples == GL_SAMPLES |
| TEST_P(SampleVariablesTest, NumSamples) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_sample_variables")); |
| |
| const char kFS[] = R"(#version 300 es |
| #extension GL_OES_sample_variables : require |
| precision highp float; |
| out vec4 color; |
| void main() |
| { |
| color = vec4(float(gl_NumSamples * 4) / 255.0, 0.0, 0.0, 1.0); |
| })"; |
| ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS); |
| |
| GLint numSampleCounts = 0; |
| glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA8, GL_NUM_SAMPLE_COUNTS, 1, &numSampleCounts); |
| ASSERT_GT(numSampleCounts, 0); |
| |
| std::vector<GLint> sampleCounts; |
| sampleCounts.resize(numSampleCounts); |
| glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA8, GL_SAMPLES, numSampleCounts, |
| sampleCounts.data()); |
| |
| sampleCounts.push_back(0); |
| |
| for (GLint sampleCount : sampleCounts) |
| { |
| 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); |
| |
| GLint samples = -1; |
| glGetIntegerv(GL_SAMPLES, &samples); |
| EXPECT_EQ(samples, sampleCount); |
| |
| drawQuad(program, essl3_shaders::PositionAttrib(), 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); |
| |
| GLubyte pixel[4]; |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel); |
| |
| EXPECT_NEAR(std::max(samples, 1) * 4, pixel[0], 1.0) << "Samples: " << sampleCount; |
| } |
| } |
| |
| // Test gl_SampleID values |
| TEST_P(SampleVariablesTest, SampleID) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_sample_variables")); |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_color_buffer_half_float")); |
| |
| const char kFS[] = R"(#version 300 es |
| #extension GL_OES_sample_variables : require |
| precision highp float; |
| out vec4 color; |
| uniform int id; |
| void main() |
| { |
| // 1.0 when the selected sample is processed, 0.0 otherwise |
| float r = float(gl_SampleID == id); |
| // Must always be 0.0 |
| float g = float(gl_SampleID < 0 || gl_SampleID >= gl_NumSamples); |
| |
| color = vec4(r, g, 0.0, 1.0); |
| })"; |
| ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS); |
| glUseProgram(program); |
| |
| GLint numSampleCounts = 0; |
| glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA16F, GL_NUM_SAMPLE_COUNTS, 1, &numSampleCounts); |
| ASSERT_GT(numSampleCounts, 0); |
| |
| std::vector<GLint> sampleCounts; |
| sampleCounts.resize(numSampleCounts); |
| glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA16F, GL_SAMPLES, numSampleCounts, |
| sampleCounts.data()); |
| |
| sampleCounts.push_back(0); |
| |
| GLFramebuffer fboResolve; |
| glBindFramebuffer(GL_FRAMEBUFFER, fboResolve); |
| |
| GLRenderbuffer rboResolve; |
| glBindRenderbuffer(GL_RENDERBUFFER, rboResolve); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA16F, 1, 1); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboResolve); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| ASSERT_GL_NO_ERROR(); |
| |
| for (GLint sampleCount : sampleCounts) |
| { |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| GLRenderbuffer rbo; |
| glBindRenderbuffer(GL_RENDERBUFFER, rbo); |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_RGBA16F, 1, 1); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| for (int sample = 0; sample < std::max(sampleCount, 1); sample++) |
| { |
| glUniform1i(glGetUniformLocation(program, "id"), sample); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); |
| drawQuad(program, essl3_shaders::PositionAttrib(), 0.0); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboResolve); |
| glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| GLfloat pixel[4]; |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fboResolve); |
| glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, pixel); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Only one sample has 1.0 value |
| EXPECT_NEAR(1.0 / std::max(sampleCount, 1), pixel[0], 0.001) |
| << "Samples: " << sampleCount << ", SampleID: " << sample; |
| EXPECT_EQ(0.0, pixel[1]); |
| } |
| } |
| } |
| |
| // Test gl_SamplePosition values |
| TEST_P(SampleVariablesTest, SamplePosition) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_sample_variables")); |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_color_buffer_half_float")); |
| |
| const char kFS[] = R"(#version 300 es |
| #extension GL_OES_sample_variables : require |
| precision highp float; |
| out vec4 color; |
| uniform int id; |
| void main() |
| { |
| vec2 rg = (gl_SampleID == id) ? gl_SamplePosition : vec2(0.0, 0.0); |
| |
| // Must always be 0.0 |
| float b = float(gl_SamplePosition.x < 0.0 || gl_SamplePosition.x > 1.0); |
| float a = float(gl_SamplePosition.y < 0.0 || gl_SamplePosition.y > 1.0); |
| |
| color = vec4(rg, b, a); |
| })"; |
| ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS); |
| glUseProgram(program); |
| |
| GLint numSampleCounts = 0; |
| glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA16F, GL_NUM_SAMPLE_COUNTS, 1, &numSampleCounts); |
| ASSERT_GT(numSampleCounts, 0); |
| |
| std::vector<GLint> sampleCounts; |
| sampleCounts.resize(numSampleCounts); |
| glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA16F, GL_SAMPLES, numSampleCounts, |
| sampleCounts.data()); |
| |
| sampleCounts.push_back(0); |
| |
| GLFramebuffer fboResolve; |
| glBindFramebuffer(GL_FRAMEBUFFER, fboResolve); |
| |
| GLRenderbuffer rboResolve; |
| glBindRenderbuffer(GL_RENDERBUFFER, rboResolve); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA16F, 1, 1); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboResolve); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| for (GLint sampleCount : sampleCounts) |
| { |
| if (sampleCount > 16) |
| { |
| // Sample positions for MSAAx32 are not defined. |
| continue; |
| } |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| GLRenderbuffer rbo; |
| glBindRenderbuffer(GL_RENDERBUFFER, rbo); |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_RGBA16F, 1, 1); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| std::unordered_set<GLfloat> positionX; |
| std::unordered_set<GLfloat> positionY; |
| for (int sample = 0; sample < std::max(sampleCount, 1); sample++) |
| { |
| glUniform1i(glGetUniformLocation(program, "id"), sample); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); |
| drawQuad(program, essl3_shaders::PositionAttrib(), 0.0); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboResolve); |
| glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| GLfloat pixel[4]; |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fboResolve); |
| glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, pixel); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Check that positions are unique for each sample |
| const int realSampleCount = std::max(sampleCount, 1); |
| EXPECT_TRUE(positionX.insert(pixel[0]).second) |
| << "Samples: " << realSampleCount << " SampleID: " << sample |
| << " X: " << (pixel[0] * realSampleCount); |
| EXPECT_TRUE(positionY.insert(pixel[1]).second) |
| << "Samples: " << realSampleCount << " SampleID: " << sample |
| << " Y: " << (pixel[1] * realSampleCount); |
| |
| // Check that sample positions are in the normalized range |
| EXPECT_EQ(0, pixel[2]); |
| EXPECT_EQ(0, pixel[3]); |
| } |
| } |
| } |
| |
| // Test gl_SampleMaskIn values |
| TEST_P(SampleVariablesTest, SampleMaskIn) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_sample_variables")); |
| |
| const char kFS[] = R"(#version 300 es |
| #extension GL_OES_sample_variables : require |
| precision highp float; |
| out vec4 color; |
| |
| uint popcount(uint v) |
| { |
| uint c = 0u; |
| for (; v != 0u; v >>= 1) c += v & 1u; |
| return c; |
| } |
| |
| void main() |
| { |
| float r = 0.0; |
| r = float(popcount(uint(gl_SampleMaskIn[0]))); |
| |
| color = vec4(r * 4.0 / 255.0, 0, 0, 1); |
| })"; |
| ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS); |
| glUseProgram(program); |
| |
| GLint numSampleCounts = 0; |
| glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA8, GL_NUM_SAMPLE_COUNTS, 1, &numSampleCounts); |
| ASSERT_GT(numSampleCounts, 0); |
| |
| std::vector<GLint> sampleCounts; |
| sampleCounts.resize(numSampleCounts); |
| glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA8, GL_SAMPLES, numSampleCounts, |
| sampleCounts.data()); |
| |
| sampleCounts.push_back(0); |
| |
| auto test = [&](GLint sampleCount, bool sampleCoverageEnabled, GLfloat coverage) { |
| if (sampleCoverageEnabled) |
| { |
| glEnable(GL_SAMPLE_COVERAGE); |
| } |
| else |
| { |
| glDisable(GL_SAMPLE_COVERAGE); |
| } |
| |
| glSampleCoverage(coverage, false); |
| |
| 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); |
| glClear(GL_COLOR_BUFFER_BIT); |
| drawQuad(program, essl3_shaders::PositionAttrib(), 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); |
| |
| GLubyte pixel[4]; |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel); |
| EXPECT_GL_NO_ERROR(); |
| |
| // Shader scales up the number of input samples to increase precision in unorm8 space. |
| int expected = std::max(sampleCount, 1) * 4; |
| |
| // Sample coverage must not affect single sampled buffers |
| if (sampleCoverageEnabled && sampleCount > 0) |
| { |
| // The number of samples in gl_SampleMaskIn must be affected by the sample |
| // coverage GL state and then the resolved value must be scaled down again. |
| expected *= coverage * coverage; |
| } |
| EXPECT_NEAR(expected, pixel[0], 1.0) |
| << "Samples: " << sampleCount |
| << ", Sample Coverage: " << (sampleCoverageEnabled ? "Enabled" : "Disabled") |
| << ", Coverage: " << coverage; |
| }; |
| |
| for (GLint sampleCount : sampleCounts) |
| { |
| if (sampleCount > 32) |
| { |
| // The test shader will not work with MSAAx64. |
| continue; |
| } |
| |
| for (bool sampleCoverageEnabled : {false, true}) |
| { |
| for (GLfloat coverage : {0.0, 0.5, 1.0}) |
| { |
| if (sampleCount == 1 && coverage != 0.0 && coverage != 1.0) |
| { |
| continue; |
| } |
| test(sampleCount, sampleCoverageEnabled, coverage); |
| } |
| } |
| } |
| } |
| |
| // Test gl_SampleMaskIn values with per-sample shading |
| TEST_P(SampleVariablesTest, SampleMaskInPerSample) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_sample_variables")); |
| |
| const char kFS[] = R"(#version 300 es |
| #extension GL_OES_sample_variables : require |
| precision highp float; |
| out vec4 color; |
| |
| void main() |
| { |
| float r = float(gl_SampleMaskIn[0] == (1 << gl_SampleID)); |
| color = vec4(r, 0, 0, 1); |
| })"; |
| ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS); |
| glUseProgram(program); |
| |
| GLint numSampleCounts = 0; |
| glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA8, GL_NUM_SAMPLE_COUNTS, 1, &numSampleCounts); |
| ASSERT_GT(numSampleCounts, 0); |
| |
| std::vector<GLint> sampleCounts; |
| sampleCounts.resize(numSampleCounts); |
| glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA8, GL_SAMPLES, numSampleCounts, |
| sampleCounts.data()); |
| |
| sampleCounts.push_back(0); |
| |
| for (GLint sampleCount : sampleCounts) |
| { |
| if (sampleCount > 32) |
| { |
| // The test shader will not work with MSAAx64. |
| continue; |
| } |
| |
| 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, essl3_shaders::PositionAttrib(), 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); |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red) << "Samples: " << sampleCount; |
| } |
| } |
| |
| // Test writing gl_SampleMask |
| TEST_P(SampleVariablesTest, SampleMask) |
| { |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_sample_variables")); |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_color_buffer_half_float")); |
| |
| const char kFS[] = R"(#version 300 es |
| #extension GL_OES_sample_variables : require |
| precision highp float; |
| uniform highp int sampleMask; |
| |
| out vec4 color; |
| |
| void main() |
| { |
| gl_SampleMask[0] = sampleMask; |
| color = vec4(1, 0, 0, 1); |
| })"; |
| ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS); |
| glUseProgram(program); |
| |
| GLint numSampleCounts = 0; |
| glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA16F, GL_NUM_SAMPLE_COUNTS, 1, &numSampleCounts); |
| ASSERT_GT(numSampleCounts, 0); |
| |
| std::vector<GLint> sampleCounts; |
| sampleCounts.resize(numSampleCounts); |
| glGetInternalformativ(GL_RENDERBUFFER, GL_RGBA16F, GL_SAMPLES, numSampleCounts, |
| sampleCounts.data()); |
| |
| sampleCounts.push_back(0); |
| |
| GLFramebuffer fboResolve; |
| glBindFramebuffer(GL_FRAMEBUFFER, fboResolve); |
| |
| GLRenderbuffer rboResolve; |
| glBindRenderbuffer(GL_RENDERBUFFER, rboResolve); |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA16F, 1, 1); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboResolve); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| auto test = [&](GLint sampleCount, GLint sampleMask, bool sampleCoverageEnabled, |
| GLfloat coverage) { |
| if (sampleCoverageEnabled) |
| { |
| glEnable(GL_SAMPLE_COVERAGE); |
| } |
| else |
| { |
| glDisable(GL_SAMPLE_COVERAGE); |
| } |
| |
| ASSERT(coverage == 0.0 || coverage == 1.0); |
| glSampleCoverage(coverage, false); |
| |
| GLFramebuffer fbo; |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| GLRenderbuffer rbo; |
| glBindRenderbuffer(GL_RENDERBUFFER, rbo); |
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_RGBA16F, 1, 1); |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); |
| ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); |
| glClear(GL_COLOR_BUFFER_BIT); |
| glUniform1i(glGetUniformLocation(program, "sampleMask"), sampleMask); |
| drawQuad(program, essl3_shaders::PositionAttrib(), 0.0); |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboResolve); |
| glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST); |
| |
| GLfloat pixel[4]; |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fboResolve); |
| glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, pixel); |
| EXPECT_GL_NO_ERROR(); |
| |
| float expected = 1.0; |
| if (sampleCount > 0) |
| { |
| if (sampleCoverageEnabled && coverage == 0.0) |
| { |
| expected = 0.0; |
| } |
| else |
| { |
| uint32_t fullSampleCount = std::max(sampleCount, 1); |
| uint32_t realSampleMask = sampleMask & (0xFFFFFFFFu >> (32 - fullSampleCount)); |
| expected = static_cast<float>(gl::BitCount(realSampleMask)) / fullSampleCount; |
| } |
| } |
| EXPECT_EQ(expected, pixel[0]) |
| << "Samples: " << sampleCount << ", gl_SampleMask[0]: " << sampleMask |
| << ", Sample Coverage: " << (sampleCoverageEnabled ? "Enabled" : "Disabled") |
| << ", Coverage: " << coverage; |
| }; |
| |
| for (GLint sampleCount : sampleCounts) |
| { |
| if (sampleCount > 32) |
| { |
| // The test shader will not work with MSAAx64. |
| continue; |
| } |
| |
| for (bool sampleCoverageEnabled : {false, true}) |
| { |
| for (GLfloat coverage : {0.0, 1.0}) |
| { |
| for (GLint sampleMask : {0xFFFFFFFFu, 0x55555555u, 0xAAAAAAAAu, 0x00000000u}) |
| { |
| test(sampleCount, sampleMask, sampleCoverageEnabled, coverage); |
| } |
| } |
| } |
| } |
| } |
| |
| GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SampleVariablesTest); |
| ANGLE_INSTANTIATE_TEST_ES3(SampleVariablesTest); |
| |
| } // anonymous namespace |