Support multisample arrays in shader programs
The added tests check that using textureSize() and texelFetch() on
textures with a fixed point format return expected results. texelFetch
is also covered for integer format textures.
dEQP GLES 3.1 tests also cover a variety of multisampled array texture
formats.
BUG=angleproject:2775
TEST=angle_end2end_tests, angle_deqp_gles31_tests
Change-Id: I99b422e24b39e3563ed72f0fb85c9c1907df807d
Reviewed-on: https://chromium-review.googlesource.com/1196521
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/tests/gl_tests/TextureMultisampleTest.cpp b/src/tests/gl_tests/TextureMultisampleTest.cpp
index 9c91611..9866ea3 100644
--- a/src/tests/gl_tests/TextureMultisampleTest.cpp
+++ b/src/tests/gl_tests/TextureMultisampleTest.cpp
@@ -7,6 +7,8 @@
// TextureMultisampleTest: Tests of multisampled texture
#include "test_utils/ANGLETest.h"
+
+#include "shader_utils.h"
#include "test_utils/gl_raii.h"
using namespace angle;
@@ -77,6 +79,50 @@
}
return maxSamples;
}
+
+ const char *blitArrayTextureLayerFragmentShader()
+ {
+ return R"(#version 310 es
+#extension GL_OES_texture_storage_multisample_2d_array : require
+precision highp float;
+precision highp int;
+
+uniform highp sampler2DMSArray tex;
+uniform int layer;
+uniform int sampleNum;
+
+in vec4 v_position;
+out vec4 my_FragColor;
+
+void main() {
+ ivec3 texSize = textureSize(tex);
+ ivec2 sampleCoords = ivec2((v_position.xy * 0.5 + 0.5) * vec2(texSize.xy - 1));
+ my_FragColor = texelFetch(tex, ivec3(sampleCoords, layer), sampleNum);
+}
+)";
+ };
+
+ const char *blitIntArrayTextureLayerFragmentShader()
+ {
+ return R"(#version 310 es
+#extension GL_OES_texture_storage_multisample_2d_array : require
+precision highp float;
+precision highp int;
+
+uniform highp isampler2DMSArray tex;
+uniform int layer;
+uniform int sampleNum;
+
+in vec4 v_position;
+out vec4 my_FragColor;
+
+void main() {
+ ivec3 texSize = textureSize(tex);
+ ivec2 sampleCoords = ivec2((v_position.xy * 0.5 + 0.5) * vec2(texSize.xy - 1));
+ my_FragColor = vec4(texelFetch(tex, ivec3(sampleCoords, layer), sampleNum));
+}
+)";
+ };
};
class TextureMultisampleTestES31 : public TextureMultisampleTest
@@ -286,6 +332,37 @@
ASSERT_GL_ERROR(GL_INVALID_ENUM);
}
+// Try to compile shaders using GL_OES_texture_storage_multisample_2d_array when the extension is
+// not enabled.
+TEST_P(TextureMultisampleArrayWebGLTest, ShaderWithoutExtension)
+{
+ const std::string &fragmentShaderRequireExtension = R"(#version 310 es
+ #extension GL_OES_texture_storage_multisample_2d_array : require
+ out highp vec4 my_FragColor;
+
+ void main() {
+ my_FragColor = vec4(0.0);
+ }
+ )";
+
+ GLuint program = CompileProgram(essl31_shaders::vs::Simple(), fragmentShaderRequireExtension);
+ EXPECT_EQ(0u, program);
+
+ const std::string &fragmentShaderEnableAndUseExtension = R"(#version 310 es
+ #extension GL_OES_texture_storage_multisample_2d_array : enable
+
+ uniform highp sampler2DMSArray tex;
+ out highp ivec4 outSize;
+
+ void main() {
+ outSize = ivec4(textureSize(tex), 0);
+ }
+ )";
+
+ program = CompileProgram(essl31_shaders::vs::Simple(), fragmentShaderEnableAndUseExtension);
+ EXPECT_EQ(0u, program);
+}
+
// Tests that GL_TEXTURE_2D_MULTISAMPLE_ARRAY is supported in GetInternalformativ.
TEST_P(TextureMultisampleArrayWebGLTest, MultisampleArrayTargetGetInternalFormativ)
{
@@ -558,6 +635,166 @@
EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::green);
}
+// Check the size of a multisample array texture in a shader.
+TEST_P(TextureMultisampleArrayWebGLTest, TextureSizeInShader)
+{
+ ANGLE_SKIP_TEST_IF(!requestArrayExtension());
+
+ const std::string &fragmentShader = R"(#version 310 es
+ #extension GL_OES_texture_storage_multisample_2d_array : require
+
+ uniform highp sampler2DMSArray tex;
+ out highp vec4 my_FragColor;
+
+ void main() {
+ my_FragColor = (textureSize(tex) == ivec3(8, 4, 2)) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1);
+ }
+ )";
+
+ ANGLE_GL_PROGRAM(texSizeProgram, essl31_shaders::vs::Simple(), fragmentShader);
+
+ GLint texLocation = glGetUniformLocation(texSizeProgram, "tex");
+ ASSERT_GE(texLocation, 0);
+
+ const GLsizei kWidth = 8;
+ const GLsizei kHeight = 4;
+
+ std::vector<GLenum> testFormats = {GL_RGBA8};
+ GLint samplesToUse = getSamplesToUse(GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES, testFormats);
+
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES, mTexture);
+ glTexStorage3DMultisampleOES(GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES, samplesToUse, GL_RGBA8,
+ kWidth, kHeight, 2, GL_TRUE);
+ ASSERT_GL_NO_ERROR();
+
+ drawQuad(texSizeProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true);
+ ASSERT_GL_NO_ERROR();
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Clear the layers of a multisample array texture, and then sample all the samples from all the
+// layers in a shader.
+TEST_P(TextureMultisampleArrayWebGLTest, SimpleTexelFetch)
+{
+ ANGLE_SKIP_TEST_IF(!requestArrayExtension());
+
+ ANGLE_GL_PROGRAM(texelFetchProgram, essl31_shaders::vs::Passthrough(),
+ blitArrayTextureLayerFragmentShader());
+
+ GLint texLocation = glGetUniformLocation(texelFetchProgram, "tex");
+ ASSERT_GE(texLocation, 0);
+ GLint layerLocation = glGetUniformLocation(texelFetchProgram, "layer");
+ ASSERT_GE(layerLocation, 0);
+ GLint sampleNumLocation = glGetUniformLocation(texelFetchProgram, "sampleNum");
+ ASSERT_GE(layerLocation, 0);
+
+ const GLsizei kWidth = 4;
+ const GLsizei kHeight = 4;
+ const GLsizei kLayerCount = 2;
+
+ std::vector<GLenum> testFormats = {GL_RGBA8};
+ GLint samplesToUse = getSamplesToUse(GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES, testFormats);
+
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES, mTexture);
+ glTexStorage3DMultisampleOES(GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES, samplesToUse, GL_RGBA8,
+ kWidth, kHeight, kLayerCount, GL_TRUE);
+ ASSERT_GL_NO_ERROR();
+
+ // Clear layer zero to green and layer one to blue.
+ glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
+ std::vector<GLColor> clearColors = {{GLColor::green, GLColor::blue}};
+ for (GLint i = 0; static_cast<GLsizei>(i) < kLayerCount; ++i)
+ {
+ glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTexture, 0, i);
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, status);
+ const GLColor &clearColor = clearColors[i];
+ glClearColor(clearColor.R / 255.0f, clearColor.G / 255.0f, clearColor.B / 255.0f,
+ clearColor.A / 255.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ ASSERT_GL_NO_ERROR();
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glUseProgram(texelFetchProgram);
+ glViewport(0, 0, kWidth, kHeight);
+ for (GLint layer = 0; static_cast<GLsizei>(layer) < kLayerCount; ++layer)
+ {
+ glUniform1i(layerLocation, layer);
+ for (GLint sampleNum = 0; sampleNum < samplesToUse; ++sampleNum)
+ {
+ glUniform1i(sampleNumLocation, sampleNum);
+ drawQuad(texelFetchProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true);
+ ASSERT_GL_NO_ERROR();
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, clearColors[layer]);
+ }
+ }
+}
+
+// Clear the layers of an integer multisample array texture, and then sample all the samples from
+// all the layers in a shader.
+TEST_P(TextureMultisampleArrayWebGLTest, IntegerTexelFetch)
+{
+ ANGLE_SKIP_TEST_IF(!requestArrayExtension());
+
+ ANGLE_GL_PROGRAM(texelFetchProgram, essl31_shaders::vs::Passthrough(),
+ blitIntArrayTextureLayerFragmentShader());
+
+ GLint texLocation = glGetUniformLocation(texelFetchProgram, "tex");
+ ASSERT_GE(texLocation, 0);
+ GLint layerLocation = glGetUniformLocation(texelFetchProgram, "layer");
+ ASSERT_GE(layerLocation, 0);
+ GLint sampleNumLocation = glGetUniformLocation(texelFetchProgram, "sampleNum");
+ ASSERT_GE(layerLocation, 0);
+
+ const GLsizei kWidth = 4;
+ const GLsizei kHeight = 4;
+ const GLsizei kLayerCount = 2;
+
+ std::vector<GLenum> testFormats = {GL_RGBA8I};
+ GLint samplesToUse = getSamplesToUse(GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES, testFormats);
+
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES, mTexture);
+ glTexStorage3DMultisampleOES(GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES, samplesToUse, GL_RGBA8I,
+ kWidth, kHeight, kLayerCount, GL_TRUE);
+ ASSERT_GL_NO_ERROR();
+
+ // Clear layer zero to green and layer one to blue.
+ glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
+ std::vector<GLColor> clearColors = {{GLColor::green, GLColor::blue}};
+ for (GLint i = 0; static_cast<GLsizei>(i) < kLayerCount; ++i)
+ {
+ glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTexture, 0, i);
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, status);
+ std::array<GLint, 4> intColor;
+ for (size_t j = 0; j < intColor.size(); ++j)
+ {
+ intColor[j] = clearColors[i][j] / 255;
+ }
+ glClearBufferiv(GL_COLOR, 0, intColor.data());
+ ASSERT_GL_NO_ERROR();
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glUseProgram(texelFetchProgram);
+ glViewport(0, 0, kWidth, kHeight);
+ for (GLint layer = 0; static_cast<GLsizei>(layer) < kLayerCount; ++layer)
+ {
+ glUniform1i(layerLocation, layer);
+ for (GLint sampleNum = 0; sampleNum < samplesToUse; ++sampleNum)
+ {
+ glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glUniform1i(sampleNumLocation, sampleNum);
+ drawQuad(texelFetchProgram, essl31_shaders::PositionAttrib(), 0.5f, 1.0f, true);
+ ASSERT_GL_NO_ERROR();
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, clearColors[layer]);
+ }
+ }
+}
+
ANGLE_INSTANTIATE_TEST(TextureMultisampleTest,
ES31_D3D11(),
ES3_OPENGL(),