| 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
|
|
|