blob: 5ed340d19de79be729ec0928f979da6a0b316923 [file] [log] [blame]
//
// 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