Index: gpu/command_buffer/tests/gl_ext_blend_func_extended_unittest.cc |
diff --git a/gpu/command_buffer/tests/gl_ext_blend_func_extended_unittest.cc b/gpu/command_buffer/tests/gl_ext_blend_func_extended_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d2f01ab58c4ec09f4df7f7f4448dae569edafb89 |
--- /dev/null |
+++ b/gpu/command_buffer/tests/gl_ext_blend_func_extended_unittest.cc |
@@ -0,0 +1,653 @@ |
+// Copyright (c) 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include <GLES2/gl2.h> |
+#include <GLES2/gl2ext.h> |
+#include <GLES2/gl2extchromium.h> |
+#include <GLES3/gl3.h> |
+ |
+#include "base/command_line.h" |
+#include "base/strings/string_number_conversions.h" |
+#include "gpu/command_buffer/service/gpu_switches.h" |
+#include "gpu/command_buffer/tests/gl_manager.h" |
+#include "gpu/command_buffer/tests/gl_test_utils.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "ui/gl/gl_switches.h" |
+ |
+#define SHADER(Src) #Src |
+#define BFE_SHADER(Src) "#extension GL_EXT_blend_func_extended : require\n" #Src |
+ |
+namespace { |
+// Partial implementation of weight function for GLES 2 blend equation that |
+// is dual-source aware. |
+template <int factor, int index> |
+float Weight(float /*dst*/[4], float src[4], float src1[4]) { |
+ if (factor == GL_SRC_COLOR) |
+ return src[index]; |
+ if (factor == GL_SRC_ALPHA) |
+ return src[3]; |
+ if (factor == GL_SRC1_COLOR_EXT) |
+ return src1[index]; |
+ if (factor == GL_SRC1_ALPHA_EXT) |
+ return src1[3]; |
+ if (factor == GL_ONE_MINUS_SRC1_COLOR_EXT) |
+ return 1.0f - src1[index]; |
+ if (factor == GL_ONE_MINUS_SRC1_ALPHA_EXT) |
+ return 1.0f - src1[3]; |
+ return 0.0f; |
+} |
+ |
+// Implementation of GLES 2 blend equation that is dual-source aware. |
+template <int RGBs, int RGBd, int As, int Ad> |
+void BlendEquationFuncAdd(float dst[4], |
+ float src[4], |
+ float src1[4], |
+ uint8 result[4]) { |
+ float r[4]; |
+ r[0] = src[0] * Weight<RGBs, 0>(dst, src, src1) + |
+ dst[0] * Weight<RGBd, 0>(dst, src, src1); |
+ r[1] = src[1] * Weight<RGBs, 1>(dst, src, src1) + |
+ dst[1] * Weight<RGBd, 1>(dst, src, src1); |
+ r[2] = src[2] * Weight<RGBs, 2>(dst, src, src1) + |
+ dst[2] * Weight<RGBd, 2>(dst, src, src1); |
+ r[3] = src[3] * Weight<As, 3>(dst, src, src1) + |
+ dst[3] * Weight<Ad, 3>(dst, src, src1); |
+ for (int i = 0; i < 4; ++i) { |
+ result[i] = static_cast<uint8>( |
+ std::floor(std::max(0.0f, std::min(1.0f, r[i])) * 255.0f)); |
+ } |
+} |
+ |
+} // namespace |
+ |
+namespace gpu { |
+ |
+class EXTBlendFuncExtendedTest : public testing::Test { |
+ public: |
+ protected: |
+ void SetUp() override { gl_.Initialize(GLManager::Options()); } |
+ |
+ void TearDown() override { gl_.Destroy(); } |
+ bool IsApplicable() const { |
+ return GLTestHelper::HasExtension("GL_EXT_blend_func_extended"); |
+ } |
+ GLManager gl_; |
+}; |
+ |
+TEST_F(EXTBlendFuncExtendedTest, TestMaxDualSourceDrawBuffers) { |
+ if (!IsApplicable()) |
+ return; |
+ |
+ GLint maxDualSourceDrawBuffers = 0; |
+ glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT, &maxDualSourceDrawBuffers); |
+ EXPECT_GT(maxDualSourceDrawBuffers, 0); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+} |
+ |
+class EXTBlendFuncExtendedDrawTest : public testing::TestWithParam<bool> { |
+ public: |
+ static const GLsizei kWidth = 100; |
+ static const GLsizei kHeight = 100; |
+ EXTBlendFuncExtendedDrawTest() : program_(0) {} |
+ |
+ protected: |
+ void SetUp() override { |
+ GLManager::Options options; |
+ options.size = gfx::Size(kWidth, kHeight); |
+ options.force_shader_name_hashing = GetParam(); |
+ base::CommandLine command_line(*base::CommandLine::ForCurrentProcess()); |
+ gl_.InitializeWithCommandLine(options, &command_line); |
+ } |
+ |
+ bool IsApplicable() const { |
+ return GLTestHelper::HasExtension("GL_EXT_blend_func_extended"); |
+ } |
+ |
+ virtual const char* GetVertexShader() { |
+ // clang-format off |
+ static const char* kVertexShader = |
+ SHADER( |
+ attribute vec4 position; |
+ void main() { |
+ gl_Position = position; |
+ }); |
+ // clang-format on |
+ return kVertexShader; |
+ } |
+ |
+ void CreateProgramWithFragmentShader(const char* fragment_shader_str) { |
+ GLuint vertex_shader = |
+ GLTestHelper::LoadShader(GL_VERTEX_SHADER, GetVertexShader()); |
+ GLuint fragment_shader = |
+ GLTestHelper::LoadShader(GL_FRAGMENT_SHADER, fragment_shader_str); |
+ ASSERT_NE(0u, vertex_shader); |
+ ASSERT_NE(0u, fragment_shader); |
+ program_ = glCreateProgram(); |
+ ASSERT_NE(0u, program_); |
+ glAttachShader(program_, vertex_shader); |
+ glAttachShader(program_, fragment_shader); |
+ glDeleteShader(vertex_shader); |
+ glDeleteShader(fragment_shader); |
+ } |
+ |
+ testing::AssertionResult LinkProgram() { |
+ glLinkProgram(program_); |
+ GLint linked = 0; |
+ glGetProgramiv(program_, GL_LINK_STATUS, &linked); |
+ if (linked == 0) { |
+ char buffer[1024]; |
+ GLsizei length = 0; |
+ glGetProgramInfoLog(program_, sizeof(buffer), &length, buffer); |
+ std::string log(buffer, length); |
+ return testing::AssertionFailure() << "Error linking program: " << log; |
+ } |
+ glUseProgram(program_); |
+ position_loc_ = glGetAttribLocation(program_, "position"); |
+ src_loc_ = glGetUniformLocation(program_, "src"); |
+ src1_loc_ = glGetUniformLocation(program_, "src1"); |
+ return testing::AssertionSuccess(); |
+ } |
+ |
+ void TearDown() override { |
+ if (program_ != 0) |
+ glDeleteProgram(program_); |
+ gl_.Destroy(); |
+ } |
+ |
+ void DrawAndVerify() { |
+ float kDst[4] = {0.5f, 0.5f, 0.5f, 0.5f}; |
+ float kSrc[4] = {1.0f, 1.0f, 1.0f, 1.0f}; |
+ float kSrc1[4] = {0.3f, 0.6f, 0.9f, 0.7f}; |
+ |
+ glUniform4f(src_loc_, kSrc[0], kSrc[1], kSrc[2], kSrc[3]); |
+ glUniform4f(src1_loc_, kSrc1[0], kSrc1[1], kSrc1[2], kSrc1[3]); |
+ |
+ GLTestHelper::SetupUnitQuad(position_loc_); |
+ |
+ glEnable(GL_BLEND); |
+ glBlendEquation(GL_FUNC_ADD); |
+ glBlendFuncSeparate(GL_SRC1_COLOR_EXT, GL_SRC_ALPHA, |
+ GL_ONE_MINUS_SRC1_COLOR_EXT, |
+ GL_ONE_MINUS_SRC1_ALPHA_EXT); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ |
+ // Draw one triangle (bottom left half). |
+ glViewport(0, 0, kWidth, kHeight); |
+ glClearColor(kDst[0], kDst[1], kDst[2], kDst[3]); |
+ glClear(GL_COLOR_BUFFER_BIT); |
+ glDrawArrays(GL_TRIANGLES, 0, 6); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ // Verify. |
+ uint8 color[4]; |
+ BlendEquationFuncAdd<GL_SRC1_COLOR_EXT, GL_SRC_ALPHA, |
+ GL_ONE_MINUS_SRC1_COLOR_EXT, |
+ GL_ONE_MINUS_SRC1_ALPHA_EXT>(kDst, kSrc, kSrc1, color); |
+ |
+ EXPECT_TRUE(GLTestHelper::CheckPixels(kWidth / 4, (3 * kHeight) / 4, 1, 1, |
+ 1, color)); |
+ EXPECT_TRUE(GLTestHelper::CheckPixels(kWidth - 1, 0, 1, 1, 1, color)); |
+ } |
+ |
+ protected: |
+ GLuint program_; |
+ GLuint position_loc_; |
+ GLuint src_loc_; |
+ GLuint src1_loc_; |
+ GLManager gl_; |
+}; |
+ |
+TEST_P(EXTBlendFuncExtendedDrawTest, ESSL1FragColor) { |
+ if (!IsApplicable()) |
+ return; |
+ // clang-format off |
+ static const char* kFragColorShader = |
+ BFE_SHADER( |
+ precision mediump float; |
+ uniform vec4 src; |
+ uniform vec4 src1; |
+ void main() { |
+ gl_FragColor = src; |
+ gl_SecondaryFragColorEXT = src1; |
+ }); |
+ // clang-format on |
+ CreateProgramWithFragmentShader(kFragColorShader); |
+ LinkProgram(); |
+ DrawAndVerify(); |
+} |
+ |
+TEST_P(EXTBlendFuncExtendedDrawTest, ESSL1FragData) { |
+ if (!IsApplicable()) |
+ return; |
+ // clang-format off |
+ static const char* kFragDataShader = |
+ BFE_SHADER( |
+ precision mediump float; |
+ uniform vec4 src; |
+ uniform vec4 src1; |
+ void main() { |
+ gl_FragData[0] = src; |
+ gl_SecondaryFragDataEXT[0] = src1; |
+ }); |
+ // clang-format on |
+ CreateProgramWithFragmentShader(kFragDataShader); |
+ LinkProgram(); |
+ DrawAndVerify(); |
+} |
+ |
+class EXTBlendFuncExtendedES3DrawTest : public EXTBlendFuncExtendedDrawTest { |
+ protected: |
+ void SetUp() override { |
+ GLManager::Options options; |
+ options.size = gfx::Size(kWidth, kHeight); |
+ options.context_type = gles2::CONTEXT_TYPE_OPENGLES3; |
+ options.force_shader_name_hashing = GetParam(); |
+ base::CommandLine command_line(*base::CommandLine::ForCurrentProcess()); |
+ command_line.AppendSwitch(switches::kEnableUnsafeES3APIs); |
+ gl_.InitializeWithCommandLine(options, &command_line); |
+ } |
+ bool IsApplicable() const { |
+ return gl_.IsInitialized() && EXTBlendFuncExtendedDrawTest::IsApplicable(); |
+ } |
+ const char* GetVertexShader() override { |
+ // clang-format off |
+ static const char* kVertexShader = |
+ "#version 300 es\n" |
+ SHADER( |
+ in vec4 position; |
+ void main() { |
+ gl_Position = position; |
+ }); |
+ // clang-format on |
+ return kVertexShader; |
+ } |
+}; |
+ |
+TEST_P(EXTBlendFuncExtendedES3DrawTest, ESSL3Var) { |
+ if (!IsApplicable()) |
+ return; |
+ // clang-format off |
+ static const char* kFragColorShader = |
+ "#version 300 es\n" |
+ BFE_SHADER( |
+ precision mediump float; |
+ uniform vec4 src; |
+ uniform vec4 src1; |
+ out vec4 FragColor; |
+ out vec4 SecondaryFragColor; |
+ void main() { |
+ FragColor = src; |
+ SecondaryFragColor = src1; |
+ }); |
+ // clang-format on |
+ CreateProgramWithFragmentShader(kFragColorShader); |
+ glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragColor"); |
+ LinkProgram(); |
+ DrawAndVerify(); |
+} |
+ |
+TEST_P(EXTBlendFuncExtendedES3DrawTest, ESSL3BindArrayWithSimpleName) { |
+ if (!IsApplicable()) |
+ return; |
+ // clang-format off |
+ static const char* kFragDataShader = |
+ "#version 300 es\n" |
+ BFE_SHADER( |
+ precision mediump float; |
+ uniform vec4 src; |
+ uniform vec4 src1; |
+ out vec4 FragData[1]; |
+ out vec4 SecondaryFragData[1]; |
+ void main() { |
+ FragData[0] = src; |
+ SecondaryFragData[0] = src1; |
+ }); |
+ // clang-format on |
+ CreateProgramWithFragmentShader(kFragDataShader); |
+ glBindFragDataLocationEXT(program_, 0, "FragData"); |
+ glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragData"); |
+ LinkProgram(); |
+ DrawAndVerify(); |
+} |
+ |
+TEST_P(EXTBlendFuncExtendedES3DrawTest, ESSL3BindSimpleVarAsArrayNoBind) { |
+ if (!IsApplicable()) |
+ return; |
+ // clang-format off |
+ static const char* kFragDataShader = |
+ "#version 300 es\n" |
+ BFE_SHADER( |
+ precision mediump float; |
+ uniform vec4 src; |
+ uniform vec4 src1; |
+ out vec4 FragData; |
+ out vec4 SecondaryFragData; |
+ void main() { |
+ FragData = src; |
+ SecondaryFragData = src1; |
+ }); |
+ // clang-format on |
+ CreateProgramWithFragmentShader(kFragDataShader); |
+ glBindFragDataLocationEXT(program_, 0, "FragData[0]"); |
+ glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragData[0]"); |
+ // Does not fail, since FragData[0] and SecondaryFragData[0] do not exist. |
+ EXPECT_TRUE(LinkProgram()); |
+ |
+ EXPECT_EQ(-1, glGetFragDataLocation(program_, "FragData[0]")); |
+ EXPECT_EQ(0, glGetFragDataLocation(program_, "FragData")); |
+ EXPECT_EQ(1, glGetFragDataLocation(program_, "SecondaryFragData")); |
+ // Did not bind index. |
+ EXPECT_EQ(0, glGetFragDataIndexEXT(program_, "SecondaryFragData")); |
+ |
+ glBindFragDataLocationEXT(program_, 0, "FragData"); |
+ glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragData"); |
+ EXPECT_TRUE(LinkProgram()); |
+ DrawAndVerify(); |
+} |
+ |
+TEST_P(EXTBlendFuncExtendedES3DrawTest, ESSL3BindArrayAsArray) { |
+ if (!IsApplicable()) |
+ return; |
+ // clang-format off |
+ static const char* kFragDataShader = |
+ "#version 300 es\n" |
+ BFE_SHADER( |
+ precision mediump float; |
+ uniform vec4 src; |
+ uniform vec4 src1; |
+ out vec4 FragData[1]; |
+ out vec4 SecondaryFragData[1]; |
+ void main() { |
+ FragData[0] = src; |
+ SecondaryFragData[0] = src1; |
+ }); |
+ // clang-format on |
+ CreateProgramWithFragmentShader(kFragDataShader); |
+ glBindFragDataLocationEXT(program_, 0, "FragData[0]"); |
+ glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragData[0]"); |
+ LinkProgram(); |
+ DrawAndVerify(); |
+} |
+ |
+TEST_P(EXTBlendFuncExtendedES3DrawTest, ES3Getters) { |
+ if (!IsApplicable()) |
+ return; |
+ // clang-format off |
+ static const char* kFragColorShader = |
+ "#version 300 es\n" |
+ BFE_SHADER( |
+ precision mediump float; |
+ uniform vec4 src; |
+ uniform vec4 src1; |
+ out vec4 FragColor; |
+ out vec4 SecondaryFragColor; |
+ void main() { |
+ FragColor = src; |
+ SecondaryFragColor = src1; |
+ }); |
+ // clang-format on |
+ CreateProgramWithFragmentShader(kFragColorShader); |
+ glBindFragDataLocationEXT(program_, 0, "FragColor"); |
+ glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragColor"); |
+ |
+ // Getters return GL error before linking. |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ GLint location = glGetFragDataLocation(program_, "FragColor"); |
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); |
+ GLint index = glGetFragDataIndexEXT(program_, "FragColor"); |
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); |
+ location = glGetFragDataLocation(program_, "SecondaryFragColor"); |
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); |
+ index = glGetFragDataIndexEXT(program_, "SecondaryFragColor"); |
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); |
+ LinkProgram(); |
+ |
+ // Getters return location and index after linking. Run twice to confirm that |
+ // setters do not affect the getters until next link. |
+ for (int i = 0; i < 2; ++i) { |
+ SCOPED_TRACE(testing::Message() << "Testing getters after link, iteration " |
+ << i); |
+ |
+ location = glGetFragDataLocation(program_, "FragColor"); |
+ EXPECT_EQ(0, location); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ index = glGetFragDataIndexEXT(program_, "FragColor"); |
+ EXPECT_EQ(0, index); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ location = glGetFragDataLocation(program_, "SecondaryFragColor"); |
+ EXPECT_EQ(0, location); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ index = glGetFragDataIndexEXT(program_, "SecondaryFragColor"); |
+ EXPECT_EQ(1, index); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ |
+ // The calls should not affect the getters until re-linking. |
+ glBindFragDataLocationEXT(program_, 0, "SecondaryFragColor"); |
+ glBindFragDataLocationIndexedEXT(program_, 0, 1, "FragColor"); |
+ } |
+ |
+ LinkProgram(); |
+ |
+ location = glGetFragDataLocation(program_, "FragColor"); |
+ EXPECT_EQ(0, location); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ index = glGetFragDataIndexEXT(program_, "FragColor"); |
+ EXPECT_EQ(1, index); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ location = glGetFragDataLocation(program_, "SecondaryFragColor"); |
+ EXPECT_EQ(0, location); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ index = glGetFragDataIndexEXT(program_, "SecondaryFragColor"); |
+ EXPECT_EQ(0, index); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ |
+ // Unknown colors return location -1, index -1. |
+ location = glGetFragDataLocation(program_, "UnknownColor"); |
+ EXPECT_EQ(-1, location); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ index = glGetFragDataIndexEXT(program_, "UnknownColor"); |
+ EXPECT_EQ(-1, index); |
+ |
+ // Reset the settings and verify that the driver gets them correct. |
+ glBindFragDataLocationEXT(program_, 0, "FragColor"); |
+ glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragColor"); |
+ LinkProgram(); |
+ DrawAndVerify(); |
+} |
+ |
+// Test that tests glBindFragDataLocationEXT, glBindFragDataLocationIndexedEXT, |
+// glGetFragDataLocation, glGetFragDataIndexEXT work correctly with |
+// GLSL array output variables. The output variable can be bound by |
+// referring to the variable name with or without the first element array |
+// accessor. The getters can query location of the individual elements in |
+// the array. The test does not actually use the base test drawing, |
+// since the drivers at the time of writing do not support multiple |
+// buffers and dual source blending. |
+TEST_P(EXTBlendFuncExtendedES3DrawTest, ES3GettersArray) { |
+ if (!IsApplicable()) |
+ return; |
+ const GLint kTestArraySize = 2; |
+ const GLint kFragData0Location = 2; |
+ const GLint kFragData1Location = 1; |
+ const GLint kUnusedLocation = 5; |
+ |
+ // The test binds kTestArraySize -sized array to location 1 for test purposes. |
+ // The GL_MAX_DRAW_BUFFERS must be > kTestArraySize, since an |
+ // array will be bound to continuous locations, starting from the first |
+ // location. |
+ GLint maxDrawBuffers = 0; |
+ glGetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers); |
+ EXPECT_LT(kTestArraySize, maxDrawBuffers); |
+ |
+ // clang-format off |
+ static const char* kFragColorShader = |
+ "#version 300 es\n" |
+ BFE_SHADER( |
+ precision mediump float; |
+ uniform vec4 src; |
+ uniform vec4 src1; |
+ out vec4 FragData[2]; |
+ void main() { |
+ FragData[0] = src; |
+ FragData[1] = src1; |
+ }); |
+ // clang-format on |
+ CreateProgramWithFragmentShader(kFragColorShader); |
+ |
+ for (int testcase = 0; testcase < 4; ++testcase) { |
+ if (testcase == 0) { |
+ glBindFragDataLocationEXT(program_, kUnusedLocation, "FragData[0]"); |
+ glBindFragDataLocationEXT(program_, kFragData0Location, "FragData"); |
+ glBindFragDataLocationEXT(program_, kFragData1Location, "FragData[1]"); |
+ } else if (testcase == 1) { |
+ glBindFragDataLocationEXT(program_, kUnusedLocation, "FragData"); |
+ glBindFragDataLocationEXT(program_, kFragData0Location, "FragData[0]"); |
+ glBindFragDataLocationEXT(program_, kFragData1Location, "FragData[1]"); |
+ } else if (testcase == 2) { |
+ glBindFragDataLocationIndexedEXT(program_, kUnusedLocation, 0, |
+ "FragData[0]"); |
+ glBindFragDataLocationIndexedEXT(program_, kFragData0Location, 0, |
+ "FragData"); |
+ glBindFragDataLocationIndexedEXT(program_, kFragData1Location, 0, |
+ "FragData[1]"); |
+ } else if (testcase == 3) { |
+ glBindFragDataLocationIndexedEXT(program_, kUnusedLocation, 0, |
+ "FragData"); |
+ glBindFragDataLocationIndexedEXT(program_, kFragData0Location, 0, |
+ "FragData[0]"); |
+ glBindFragDataLocationIndexedEXT(program_, kFragData1Location, 0, |
+ "FragData[1]"); |
+ } |
+ |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ LinkProgram(); |
+ EXPECT_EQ(kFragData0Location, glGetFragDataLocation(program_, "FragData")); |
+ EXPECT_EQ(0, glGetFragDataIndexEXT(program_, "FragData")); |
+ EXPECT_EQ(kFragData0Location, |
+ glGetFragDataLocation(program_, "FragData[0]")); |
+ EXPECT_EQ(0, glGetFragDataIndexEXT(program_, "FragData[0]")); |
+ EXPECT_EQ(kFragData1Location, |
+ glGetFragDataLocation(program_, "FragData[1]")); |
+ EXPECT_EQ(0, glGetFragDataIndexEXT(program_, "FragData[1]")); |
+ |
+ // Index bigger than the GLSL variable array length does not find anything. |
+ EXPECT_EQ(-1, glGetFragDataLocation(program_, "FragData[3]")); |
+ } |
+} |
+ |
+// Test that tests glBindFragDataLocationEXT, glBindFragDataLocationIndexedEXT |
+// conflicts |
+// with GLSL output variables. |
+TEST_P(EXTBlendFuncExtendedES3DrawTest, ES3Conflicts) { |
+ if (!IsApplicable()) |
+ return; |
+ const GLint kTestArraySize = 2; |
+ const GLint kColorName0Location = 0; |
+ const GLint kColorName1Location = 1; |
+ GLint maxDrawBuffers = 0; |
+ glGetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers); |
+ EXPECT_LT(kTestArraySize, maxDrawBuffers); |
+ |
+ // clang-format off |
+ static const char* kFragColorShader = |
+ "#version 300 es\n" |
+ BFE_SHADER( |
+ precision mediump float; |
+ uniform vec4 src; |
+ uniform vec4 src1; |
+ out vec4 FragData0; |
+ out vec4 FragData1; |
+ void main() { |
+ FragData0 = src; |
+ FragData1 = src1; |
+ }); |
+ // clang-format on |
+ CreateProgramWithFragmentShader(kFragColorShader); |
+ |
+ glBindFragDataLocationEXT(program_, kColorName0Location, "FragData0"); |
+ glBindFragDataLocationEXT(program_, kColorName0Location, "FragData1"); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ EXPECT_FALSE(LinkProgram()); |
+ |
+ glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 0, |
+ "FragData0"); |
+ glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 0, |
+ "FragData1"); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ EXPECT_FALSE(LinkProgram()); |
+ |
+ glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 1, |
+ "FragData0"); |
+ glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 1, |
+ "FragData1"); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ EXPECT_FALSE(LinkProgram()); |
+ |
+ // Test that correct binding actually works. |
+ glBindFragDataLocationEXT(program_, kColorName0Location, "FragData0"); |
+ glBindFragDataLocationEXT(program_, kColorName1Location, "FragData1"); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ EXPECT_TRUE(LinkProgram()); |
+ |
+ glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 0, |
+ "FragData0"); |
+ glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 1, |
+ "FragData1"); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ EXPECT_TRUE(LinkProgram()); |
+} |
+ |
+// Test that tests glBindFragDataLocationEXT conflicts |
+// with GLSL array output variables. |
+TEST_P(EXTBlendFuncExtendedES3DrawTest, ES3ConflictsArray) { |
+ if (!IsApplicable()) |
+ return; |
+ const GLint kTestArraySize = 2; |
+ const GLint kColorName0Location = 0; |
+ const GLint kColorName1Location = 1; |
+ const GLint kUnusedLocation = 5; |
+ GLint maxDrawBuffers = 0; |
+ glGetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers); |
+ EXPECT_LT(kTestArraySize, maxDrawBuffers); |
+ |
+ // clang-format off |
+ static const char* kFragColorShader = |
+ "#version 300 es\n" |
+ BFE_SHADER( |
+ precision mediump float; |
+ uniform vec4 src; |
+ uniform vec4 src1; |
+ out vec4 FragData[2]; |
+ void main() { |
+ FragData[0] = src; |
+ FragData[1] = src1; |
+ }); |
+ // clang-format on |
+ CreateProgramWithFragmentShader(kFragColorShader); |
+ |
+ glBindFragDataLocationEXT(program_, kColorName1Location, "FragData"); |
+ glBindFragDataLocationEXT(program_, kColorName1Location, "FragData[1]"); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ EXPECT_FALSE(LinkProgram()); |
+ glBindFragDataLocationEXT(program_, kUnusedLocation, "FragData"); |
+ glBindFragDataLocationEXT(program_, kColorName1Location, "FragData[0]"); |
+ glBindFragDataLocationEXT(program_, kColorName1Location, "FragData[1]"); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ EXPECT_FALSE(LinkProgram()); |
+ // Test that binding actually works. |
+ glBindFragDataLocationEXT(program_, kColorName0Location, "FragData[0]"); |
+ glBindFragDataLocationEXT(program_, kColorName1Location, "FragData[1]"); |
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
+ EXPECT_TRUE(LinkProgram()); |
+} |
+ |
+INSTANTIATE_TEST_CASE_P(TranslatorVariants, |
+ EXTBlendFuncExtendedDrawTest, |
+ ::testing::Bool()); |
+ |
+INSTANTIATE_TEST_CASE_P(TranslatorVariants, |
+ EXTBlendFuncExtendedES3DrawTest, |
+ ::testing::Bool()); |
+ |
+} // namespace gpu |