blob: 7d4ecbd7dc618a3da8ee9fb515ee1b37fd34ba35 [file] [edit]
//
// Copyright 2025 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.
//
#include "test_utils/ANGLETest.h"
#include "test_utils/angle_test_configs.h"
#include "test_utils/gl_raii.h"
#include "util/shader_utils.h"
namespace
{
using namespace angle;
class GLSLUBTest : public ANGLETest<>
{
protected:
GLSLUBTest()
{
setWindowWidth(128);
setWindowHeight(128);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
}
};
// grep TEST_P src/tests/gl_tests/GLSLUBTest.cpp
// For prefixes Add, Sub find:
// IntInt
// IntIvec
// IvecInt
// IvecIvec
// AssignIvecInt
// AssignIvecIvec
// Test int + int with overflow. Expect wraparound.
TEST_P(GLSLUBTest, AddIntIntOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
int r0 = u + -1;
int r1 = u + 0;
int r2 = 2147483646 + u;
int r3 = u + 2147483647;
gl_FragColor.r = r0 == 1 ? 1.0 : 0.0;
gl_FragColor.g = r1 == 2 ? 1.0 : 0.0;
gl_FragColor.b = r2 == -2147483648 ? 1.0 : 0.0;
gl_FragColor.a = r3 == -2147483647 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, 2);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int + ivec overflow. Expect wraparound.
TEST_P(GLSLUBTest, AddIntIvecOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
ivec4 r = u + ivec4(0, -1, 1, 2147483647);
gl_FragColor.r = r.x == 2 ? 1.0 : 0.0;
gl_FragColor.g = r.y == 1 ? 1.0 : 0.0;
gl_FragColor.b = r.z == 3 ? 1.0 : 0.0;
gl_FragColor.a = r.w == -2147483647 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, 2);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int + ivec overflow. Expect wraparound.
TEST_P(GLSLUBTest, AddIvecIntOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
ivec4 r = ivec4(0, -1, 1, 2147483647) + u;
gl_FragColor.r = r.x == 2 ? 1.0 : 0.0;
gl_FragColor.g = r.y == 1 ? 1.0 : 0.0;
gl_FragColor.b = r.z == 3 ? 1.0 : 0.0;
gl_FragColor.a = r.w == -2147483647 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, 2);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test ivec + ivec, ivec + int overflow. Expect wraparound.
TEST_P(GLSLUBTest, AddIvecIvecOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform ivec4 u;
void main() {
ivec4 r0 = u + ivec4(0, -1, 1, 2147483647);
ivec4 r1 = ivec4(0, -1, 1, 2147483647) + u;
gl_FragColor.r = r0 == r1 ? 1.0 : 0.0;
gl_FragColor.g = r0.y == 1 ? 1.0 : 0.0;
gl_FragColor.b = r0.z == 3 ? 1.0 : 0.0;
gl_FragColor.a = r0.w == -2147483647 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform4i(u, 2, 2, 2, 2);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test highp ivec += int overflow. Expect wraparound.
TEST_P(GLSLUBTest, AddAssignIvecIntOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
ivec4 r = ivec4(0, -1, 1, 2147483647);
r += u;
gl_FragColor.r = r.x == 2 ? 1.0 : 0.0;
gl_FragColor.g = r.y == 1 ? 1.0 : 0.0;
gl_FragColor.b = r.z == 3 ? 1.0 : 0.0;
gl_FragColor.a = r.w == -2147483647 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, 2);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test highp ivec += ivec overflow. Expect wraparound.
TEST_P(GLSLUBTest, AddAssignIvecIvecOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform ivec4 u;
void main() {
ivec4 r = ivec4(0, -1, 1, 2147483647);
r += u;
gl_FragColor.r = r.x == 2 ? 1.0 : 0.0;
gl_FragColor.g = r.y == 1 ? 1.0 : 0.0;
gl_FragColor.b = r.z == 3 ? 1.0 : 0.0;
gl_FragColor.a = r.w == -2147483647 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform4i(u, 2, 2, 2, 2);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int - int with overflow. Expect wraparound.
TEST_P(GLSLUBTest, SubIntIntOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
int r0 = u - (-1);
int r1 = u - 0;
int r2 = -2147483646 - u;
int r3 = u - (-2147483647);
gl_FragColor.r = r0 == 3 ? 1.0 : 0.0;
gl_FragColor.g = r1 == 2 ? 1.0 : 0.0;
gl_FragColor.b = r2 == 2147483648 ? 1.0 : 0.0;
gl_FragColor.a = r3 == -2147483647 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, 2);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test highp int - ivec underflow. Expect wraparound.
TEST_P(GLSLUBTest, SubIntIvecUnderflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
ivec4 r = u - ivec4(0, -1, 1, 2147483647);
gl_FragColor.r = r.x == 2 ? 1.0 : 0.0;
gl_FragColor.g = r.y == 3 ? 1.0 : 0.0;
gl_FragColor.b = r.z == 1 ? 1.0 : 0.0;
gl_FragColor.a = r.w == -2147483645 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, 2);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test highp ivec - int underflow. Expect wraparound.
TEST_P(GLSLUBTest, SubIvecIntUnderflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
ivec4 r = ivec4(0, -1, 1, -2147483647) - u;
gl_FragColor.r = r.x == -2 ? 1.0 : 0.0;
gl_FragColor.g = r.y == -3 ? 1.0 : 0.0;
gl_FragColor.b = r.z == -1 ? 1.0 : 0.0;
gl_FragColor.a = r.w == 2147483647 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, 2);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test highp int vec -= scalar underflow. Expect wraparound.
TEST_P(GLSLUBTest, SubAssignIvecIntUnderflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
ivec4 r = ivec4(0, -1, 1, -2147483647);
r -= u;
gl_FragColor.r = r.x == -2 ? 1.0 : 0.0;
gl_FragColor.g = r.y == -3 ? 1.0 : 0.0;
gl_FragColor.b = r.z == -1 ? 1.0 : 0.0;
gl_FragColor.a = r.w == 2147483647 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, 2);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test highp int vec -= scalar underflow. Expect wraparound.
TEST_P(GLSLUBTest, SubAssignIvecIvecUnderflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform ivec4 u;
void main() {
ivec4 r = ivec4(0, -1, 1, -2147483647);
r -= u;
gl_FragColor.r = r.x == -2 ? 1.0 : 0.0;
gl_FragColor.g = r.y == -3 ? 1.0 : 0.0;
gl_FragColor.b = r.z == -1 ? 1.0 : 0.0;
gl_FragColor.a = r.w == 2147483647 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform4i(u, 2, 2, 2, 2);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test ++int with overflow. Expect wraparound.
TEST_P(GLSLUBTest, PreIncrementIntOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
int r0 = u;
int r1 = ++r0;
gl_FragColor.r = r0 == -2147483648 ? 1.0 : 0.0;
gl_FragColor.g = r1 == -2147483648 ? 1.0 : 0.0;
gl_FragColor.b = u == 2147483647 ? 1.0 : 0.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, 2147483647);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int++ with overflow. Expect wraparound.
TEST_P(GLSLUBTest, PostIncrementIntOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
int r0 = u;
int r1 = r0++;
gl_FragColor.r = r0 == -2147483648 ? 1.0 : 0.0;
gl_FragColor.g = r1 == 2147483647 ? 1.0 : 0.0;
gl_FragColor.b = u == 2147483647 ? 1.0 : 0.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, 2147483647);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test --int with overflow. Expect wraparound.
TEST_P(GLSLUBTest, PreDecrementIntOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
int r0 = u;
int r1 = --r0;
gl_FragColor.r = r0 == 2147483648 ? 1.0 : 0.0;
gl_FragColor.g = r1 == 2147483648 ? 1.0 : 0.0;
gl_FragColor.b = u == -2147483647 ? 1.0 : 0.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, -2147483647);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int-- with overflow. Expect wraparound.
TEST_P(GLSLUBTest, PostDecrementIntOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
int r0 = u;
int r1 = r0--;
gl_FragColor.r = r0 == 2147483648 ? 1.0 : 0.0;
gl_FragColor.g = r1 == -2147483647 ? 1.0 : 0.0;
gl_FragColor.b = u == -2147483647 ? 1.0 : 0.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, -2147483647);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test ++ivec with overflow. Expect wraparound.
TEST_P(GLSLUBTest, PreIncrementIvecOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform ivec4 u;
void main() {
ivec4 r0 = u;
ivec4 r1 = ++r0;
gl_FragColor.r = r0 == ivec4(1, 2, 3, -2147483648) ? 1.0 : 0.0;
gl_FragColor.g = r1 == ivec4(1, 2, 3, -2147483648) ? 1.0 : 0.0;
gl_FragColor.b = u == ivec4(0, 1, 2, 2147483647) ? 1.0 : 0.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform4i(u, 0, 1, 2, 2147483647);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test ivec++ with overflow. Expect wraparound.
TEST_P(GLSLUBTest, PostIncrementIvecOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform ivec4 u;
void main() {
ivec4 r0 = u;
ivec4 r1 = r0++;
gl_FragColor.r = r0 == ivec4(1, 2, 3, -2147483648) ? 1.0 : 0.0;
gl_FragColor.g = r1 == ivec4(0, 1, 2, 2147483647) ? 1.0 : 0.0;
gl_FragColor.b = u == ivec4(0, 1, 2, 2147483647) ? 1.0 : 0.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform4i(u, 0, 1, 2, 2147483647);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test --ivec with overflow. Expect wraparound.
TEST_P(GLSLUBTest, PreDecrementIvecOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform ivec4 u;
void main() {
ivec4 r0 = u;
ivec4 r1 = --r0;
gl_FragColor.r = r0 == ivec4(-1, 0, 1, 2147483648) ? 1.0 : 0.0;
gl_FragColor.g = r1 == ivec4(-1, 0, 1, 2147483648) ? 1.0 : 0.0;
gl_FragColor.b = u == ivec4(0, 1, 2, -2147483647) ? 1.0 : 0.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform4i(u, 0, 1, 2, -2147483647);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test ivec-- with overflow. Expect wraparound.
TEST_P(GLSLUBTest, PostDecrementIvecOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform ivec4 u;
void main() {
ivec4 r0 = u;
ivec4 r1 = r0--;
gl_FragColor.r = r0 == ivec4(-1, 0, 1, 2147483648) ? 1.0 : 0.0;
gl_FragColor.g = r1 == ivec4(0, 1, 2, -2147483647) ? 1.0 : 0.0;
gl_FragColor.b = u == ivec4(0, 1, 2, -2147483647) ? 1.0 : 0.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform4i(u, 0, 1, 2, -2147483647);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int++ with overflow. Expect wraparound.
TEST_P(GLSLUBTest, PostIncrementIntOverflowInForDynamic)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
int z = 0;
for (int i = u; i > 4; i++) {
z++;
}
gl_FragColor.r = z == 7 ? 1.0 : 0.0;
gl_FragColor.g = u == 2147483641 ? 1.0 : 0.0;
gl_FragColor.b = 1.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, 2147483641);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int++ with overflow. Expect wraparound.
TEST_P(GLSLUBTest, PostIncrementIntOverflowInForStatic)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
void main() {
int z = 0;
for (int i = 2147483642; i > 4; i++) {
z++;
}
gl_FragColor.r = z == 6 ? 1.0 : 0.0;
gl_FragColor.g = 1.0;
gl_FragColor.b = 1.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test abs() on the smallest negative int. The spec defines abs(x) as -x for negative x, and that
// negation overflows, so expect wraparound, i.e. the value is unchanged.
TEST_P(GLSLUBTest, AbsIntOverflow)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
constexpr char kFS[] = R"(#version 300 es
precision highp int;
precision highp float;
uniform int u;
uniform ivec4 uv;
out vec4 color;
void main() {
int r0 = abs(u);
ivec4 r1 = abs(uv);
color.r = r0 == -2147483648 ? 1.0 : 0.0;
color.g = r1 == ivec4(0, 1, 2147483647, -2147483648) ? 1.0 : 0.0;
// abs() of a negative value is negative only when it overflows.
color.b = abs(u) < 0 ? 1.0 : 0.0;
color.a = abs(u) == u ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint uv = glGetUniformLocation(testProgram, "uv");
EXPECT_NE(-1, uv);
glUniform1i(u, -2147483647 - 1);
glUniform4i(uv, 0, -1, -2147483647, -2147483647 - 1);
drawQuad(testProgram, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test unary - on the smallest negative int, which overflows. Expect wraparound, i.e. the value is
// unchanged. The comparisons are written so that a compiler that assumes the negation cannot
// overflow can fold them to a constant.
TEST_P(GLSLUBTest, NegateIntOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
int r0 = -u;
int r1 = -(-u);
gl_FragColor.r = r0 == -2147483648 ? 1.0 : 0.0;
gl_FragColor.g = r1 == -2147483648 ? 1.0 : 0.0;
// -u == u only holds for 0 and for the smallest negative value.
gl_FragColor.b = -u == u ? 1.0 : 0.0;
// The negation of a negative value is negative only when it overflows.
gl_FragColor.a = -u < 0 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, -2147483647 - 1);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test unary - on an ivec containing the smallest negative int. Expect wraparound.
TEST_P(GLSLUBTest, NegateIvecOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform ivec4 u;
void main() {
ivec4 r0 = -u;
ivec4 r1 = -(-u);
gl_FragColor.r = r0 == ivec4(0, -1, -2147483647, -2147483648) ? 1.0 : 0.0;
gl_FragColor.g = r1 == u ? 1.0 : 0.0;
gl_FragColor.b = -u.w == u.w ? 1.0 : 0.0;
gl_FragColor.a = -u.w < 0 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform4i(u, 0, 1, 2147483647, -2147483647 - 1);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int * int with overflow. Expect wraparound.
TEST_P(GLSLUBTest, MulIntIntOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
int r0 = u * u;
int r1 = u * 32768;
int r2 = 49152 * u;
int r3 = u * -49152;
gl_FragColor.r = r0 == 0 ? 1.0 : 0.0;
gl_FragColor.g = r1 == -2147483648 ? 1.0 : 0.0;
gl_FragColor.b = r2 == -1073741824 ? 1.0 : 0.0;
gl_FragColor.a = r3 == 1073741824 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, 65536);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int * ivec with overflow. Expect wraparound.
TEST_P(GLSLUBTest, MulIntIvecOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
ivec4 r = u * ivec4(1, 32768, 49152, -49152);
gl_FragColor.r = r.x == 65536 ? 1.0 : 0.0;
gl_FragColor.g = r.y == -2147483648 ? 1.0 : 0.0;
gl_FragColor.b = r.z == -1073741824 ? 1.0 : 0.0;
gl_FragColor.a = r.w == 1073741824 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, 65536);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test ivec * int with overflow. Expect wraparound.
TEST_P(GLSLUBTest, MulIvecIntOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
ivec4 r = ivec4(1, 32768, 49152, -49152) * u;
gl_FragColor.r = r.x == 65536 ? 1.0 : 0.0;
gl_FragColor.g = r.y == -2147483648 ? 1.0 : 0.0;
gl_FragColor.b = r.z == -1073741824 ? 1.0 : 0.0;
gl_FragColor.a = r.w == 1073741824 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, 65536);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test ivec * ivec with overflow. Expect wraparound.
TEST_P(GLSLUBTest, MulIvecIvecOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform ivec4 u;
void main() {
ivec4 r = u * u;
gl_FragColor.r = r.x == 0 ? 1.0 : 0.0;
gl_FragColor.g = r.y == 1073741824 ? 1.0 : 0.0;
gl_FragColor.b = r.z == -1879048192 ? 1.0 : 0.0;
gl_FragColor.a = r.w == -1879048192 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform4i(u, 65536, 32768, 49152, -49152);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int *= int with overflow. Expect wraparound.
TEST_P(GLSLUBTest, MulAssignIntIntOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
int r0 = u;
r0 *= u;
int r1 = 32768;
r1 *= u;
gl_FragColor.r = r0 == 0 ? 1.0 : 0.0;
gl_FragColor.g = r1 == -2147483648 ? 1.0 : 0.0;
gl_FragColor.b = u == 65536 ? 1.0 : 0.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, 65536);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test ivec *= int and ivec *= ivec with overflow. Expect wraparound.
TEST_P(GLSLUBTest, MulAssignIvecOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void main() {
ivec4 r0 = ivec4(1, 32768, 49152, -49152);
r0 *= u;
ivec4 r1 = ivec4(1, 32768, 49152, -49152);
r1 *= ivec4(u);
gl_FragColor.r = r0 == ivec4(65536, -2147483648, -1073741824, 1073741824) ? 1.0 : 0.0;
gl_FragColor.g = r0 == r1 ? 1.0 : 0.0;
gl_FragColor.b = 1.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, 65536);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int / int where the divisor is 0. GLSL ES 3.00 section 5.9 makes this an unspecified value,
// so the value asserted here is only what the emulation happens to produce, which is the dividend.
// The well defined divisions must not be affected.
TEST_P(GLSLUBTest, DivIntIntByZero)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
uniform int z;
void main() {
int r0 = u / z;
int r1 = -u / z;
int r2 = u / 2;
int r3 = z / u;
gl_FragColor.r = r0 == 7 ? 1.0 : 0.0;
gl_FragColor.g = r1 == -7 ? 1.0 : 0.0;
gl_FragColor.b = r2 == 3 ? 1.0 : 0.0;
gl_FragColor.a = r3 == 0 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint z = glGetUniformLocation(testProgram, "z");
EXPECT_NE(-1, z);
glUniform1i(u, 7);
glUniform1i(z, 0);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test the int / int case that overflows, i.e. dividing the smallest negative value by -1. The
// spec allows either the smallest or the largest representable value to be returned here (GLSL ES
// 3.00 section 4.1.3), and the emulation returns the smallest, which is what is asserted.
TEST_P(GLSLUBTest, DivIntIntOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
uniform int m;
void main() {
int r0 = u / m;
int r1 = u / 2;
int r2 = (u + 1) / m;
int r3 = u / 1;
gl_FragColor.r = r0 == -2147483648 ? 1.0 : 0.0;
gl_FragColor.g = r1 == -1073741824 ? 1.0 : 0.0;
gl_FragColor.b = r2 == 2147483647 ? 1.0 : 0.0;
gl_FragColor.a = r3 == -2147483648 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint m = glGetUniformLocation(testProgram, "m");
EXPECT_NE(-1, m);
glUniform1i(u, -2147483647 - 1);
glUniform1i(m, -1);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test ivec / ivec, ivec / int and ivec /= int with a 0 divisor and with an overflow.
TEST_P(GLSLUBTest, DivIvecByZero)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform ivec4 u;
uniform ivec4 zv;
uniform int z;
void main() {
ivec4 r0 = u / zv;
ivec4 r1 = u / z;
ivec4 r2 = u;
r2 /= z;
gl_FragColor.r = r0 == ivec4(7, -7, 0, -2147483648) ? 1.0 : 0.0;
gl_FragColor.g = r1 == u ? 1.0 : 0.0;
gl_FragColor.b = r2 == u ? 1.0 : 0.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint zv = glGetUniformLocation(testProgram, "zv");
EXPECT_NE(-1, zv);
GLint z = glGetUniformLocation(testProgram, "z");
EXPECT_NE(-1, z);
glUniform4i(u, 7, -7, 0, -2147483647 - 1);
glUniform4i(zv, 0, 0, 0, -1);
glUniform1i(z, 0);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int /= int where the divisor is 0.
TEST_P(GLSLUBTest, DivAssignIntIntByZero)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
uniform int z;
void main() {
int r0 = u;
r0 /= z;
int r1 = u;
r1 /= 2;
gl_FragColor.r = r0 == 7 ? 1.0 : 0.0;
gl_FragColor.g = r1 == 3 ? 1.0 : 0.0;
gl_FragColor.b = 1.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint z = glGetUniformLocation(testProgram, "z");
EXPECT_NE(-1, z);
glUniform1i(u, 7);
glUniform1i(z, 0);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test uint / uint where the divisor is 0.
TEST_P(GLSLUBTest, DivUintUintByZero)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
constexpr char kFS[] = R"(#version 300 es
precision highp int;
precision highp float;
uniform uint u;
uniform uint z;
out vec4 color;
void main() {
uint r0 = u / z;
uint r1 = u / 2u;
uvec4 r2 = uvec4(u) / uvec4(z);
color.r = r0 == 7u ? 1.0 : 0.0;
color.g = r1 == 3u ? 1.0 : 0.0;
color.b = r2 == uvec4(7u) ? 1.0 : 0.0;
color.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint z = glGetUniformLocation(testProgram, "z");
EXPECT_NE(-1, z);
glUniform1ui(u, 7u);
glUniform1ui(z, 0u);
drawQuad(testProgram, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int % int where the divisor is 0. GLSL ES 3.00 section 5.9 leaves the result undefined per
// component, so the value asserted here is only what the emulation produces, which is 0. The well
// defined remainders must not be affected.
TEST_P(GLSLUBTest, ModIntIntByZero)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
constexpr char kFS[] = R"(#version 300 es
precision highp int;
precision highp float;
uniform int u;
uniform int z;
out vec4 color;
void main() {
int r0 = u % z;
int r1 = -u % z;
int r2 = u % 2;
int r3 = z % u;
color.r = r0 == 0 ? 1.0 : 0.0;
color.g = r1 == 0 ? 1.0 : 0.0;
color.b = r2 == 1 ? 1.0 : 0.0;
color.a = r3 == 0 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint z = glGetUniformLocation(testProgram, "z");
EXPECT_NE(-1, z);
glUniform1i(u, 7);
glUniform1i(z, 0);
drawQuad(testProgram, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test the int % int case where the corresponding division overflows, i.e. the smallest negative
// value modulo -1. GLSL ES 3.00 section 5.9 leaves the result undefined because an operand is
// negative, and the emulation returns the mathematically correct 0, which is what is asserted.
TEST_P(GLSLUBTest, ModIntIntOverflow)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
constexpr char kFS[] = R"(#version 300 es
precision highp int;
precision highp float;
uniform int u;
uniform int m;
out vec4 color;
void main() {
int r0 = u % m;
int r1 = u % 2;
int r2 = (u + 1) % m;
int r3 = u % 1;
color.r = r0 == 0 ? 1.0 : 0.0;
color.g = r1 == 0 ? 1.0 : 0.0;
color.b = r2 == 0 ? 1.0 : 0.0;
color.a = r3 == 0 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint m = glGetUniformLocation(testProgram, "m");
EXPECT_NE(-1, m);
glUniform1i(u, -2147483647 - 1);
glUniform1i(m, -1);
drawQuad(testProgram, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int % int with negative operands, which GLSL ES 3.00 section 5.9 leaves undefined. The
// emulation truncates towards zero, so the sign follows the dividend, which is what is asserted.
TEST_P(GLSLUBTest, ModIntIntNegative)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
constexpr char kFS[] = R"(#version 300 es
precision highp int;
precision highp float;
uniform int a;
uniform int b;
out vec4 color;
void main() {
int r0 = -a % b;
int r1 = a % -b;
int r2 = -a % -b;
int r3 = a % b;
color.r = r0 == -1 ? 1.0 : 0.0;
color.g = r1 == 1 ? 1.0 : 0.0;
color.b = r2 == -1 ? 1.0 : 0.0;
color.a = r3 == 1 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint a = glGetUniformLocation(testProgram, "a");
EXPECT_NE(-1, a);
GLint b = glGetUniformLocation(testProgram, "b");
EXPECT_NE(-1, b);
glUniform1i(a, 7);
glUniform1i(b, 3);
drawQuad(testProgram, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test ivec % ivec, ivec % int and ivec %= int with a 0 divisor and with an overflow.
TEST_P(GLSLUBTest, ModIvecByZero)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
constexpr char kFS[] = R"(#version 300 es
precision highp int;
precision highp float;
uniform ivec4 u;
uniform ivec4 zv;
uniform int z;
out vec4 color;
void main() {
ivec4 r0 = u % zv;
ivec4 r1 = u % z;
ivec4 r2 = u;
r2 %= z;
color.r = r0 == ivec4(0) ? 1.0 : 0.0;
color.g = r1 == ivec4(0) ? 1.0 : 0.0;
color.b = r2 == ivec4(0) ? 1.0 : 0.0;
color.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint zv = glGetUniformLocation(testProgram, "zv");
EXPECT_NE(-1, zv);
GLint z = glGetUniformLocation(testProgram, "z");
EXPECT_NE(-1, z);
glUniform4i(u, 7, -7, 0, -2147483647 - 1);
glUniform4i(zv, 0, 0, 0, -1);
glUniform1i(z, 0);
drawQuad(testProgram, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test uint % uint where the divisor is 0.
TEST_P(GLSLUBTest, ModUintUintByZero)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
constexpr char kFS[] = R"(#version 300 es
precision highp int;
precision highp float;
uniform uint u;
uniform uint z;
out vec4 color;
void main() {
uint r0 = u % z;
uint r1 = u % 2u;
uvec4 r2 = uvec4(u);
r2 %= z;
color.r = r0 == 0u ? 1.0 : 0.0;
color.g = r1 == 1u ? 1.0 : 0.0;
color.b = r2 == uvec4(0u) ? 1.0 : 0.0;
color.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint z = glGetUniformLocation(testProgram, "z");
EXPECT_NE(-1, z);
glUniform1ui(u, 7u);
glUniform1ui(z, 0u);
drawQuad(testProgram, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int << int with a shift amount that is out of range. The result is undefined, so this only
// tests that the shader runs. The emulation masks the shift amount to 5 bits, so shifting by 32
// shifts by 0 and shifting by -1 shifts by 31.
TEST_P(GLSLUBTest, ShiftLeftIntAmountOutOfRange)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
constexpr char kFS[] = R"(#version 300 es
precision highp int;
precision highp float;
uniform int u;
uniform int big;
uniform int neg;
out vec4 color;
void main() {
int r0 = u << big;
int r1 = u << neg;
int r2 = u << 31;
int r3 = u << 0;
color.r = r0 == 1 ? 1.0 : 0.0;
color.g = r1 == -2147483648 ? 1.0 : 0.0;
color.b = r2 == -2147483648 ? 1.0 : 0.0;
color.a = r3 == 1 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint big = glGetUniformLocation(testProgram, "big");
EXPECT_NE(-1, big);
GLint neg = glGetUniformLocation(testProgram, "neg");
EXPECT_NE(-1, neg);
glUniform1i(u, 1);
glUniform1i(big, 32);
glUniform1i(neg, -1);
drawQuad(testProgram, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int << int where the value is negative or where the shift overflows. Expect the bits to be
// shifted out.
TEST_P(GLSLUBTest, ShiftLeftIntNegativeValue)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
constexpr char kFS[] = R"(#version 300 es
precision highp int;
precision highp float;
uniform int u;
uniform int h;
out vec4 color;
void main() {
int r0 = u << 1;
int r1 = u << 31;
int r2 = h << 1;
int r3 = h << 2;
color.r = r0 == -2 ? 1.0 : 0.0;
color.g = r1 == -2147483648 ? 1.0 : 0.0;
color.b = r2 == -2147483648 ? 1.0 : 0.0;
color.a = r3 == 0 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint h = glGetUniformLocation(testProgram, "h");
EXPECT_NE(-1, h);
glUniform1i(u, -1);
glUniform1i(h, 1073741824);
drawQuad(testProgram, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int >> int with a shift amount that is out of range. The result is undefined, so this only
// tests that the shader runs. The emulation masks the shift amount to 5 bits. The in range shifts
// must sign extend.
TEST_P(GLSLUBTest, ShiftRightIntAmountOutOfRange)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
constexpr char kFS[] = R"(#version 300 es
precision highp int;
precision highp float;
uniform int u;
uniform int big;
uniform int neg;
out vec4 color;
void main() {
int r0 = u >> big;
int r1 = u >> neg;
int r2 = u >> 1;
int r3 = u >> 31;
color.r = r0 == -8 ? 1.0 : 0.0;
color.g = r1 == -1 ? 1.0 : 0.0;
color.b = r2 == -4 ? 1.0 : 0.0;
color.a = r3 == -1 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint big = glGetUniformLocation(testProgram, "big");
EXPECT_NE(-1, big);
GLint neg = glGetUniformLocation(testProgram, "neg");
EXPECT_NE(-1, neg);
glUniform1i(u, -8);
glUniform1i(big, 32);
glUniform1i(neg, -1);
drawQuad(testProgram, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test uint << uint and uint >> uint with a shift amount that is out of range.
TEST_P(GLSLUBTest, ShiftUintAmountOutOfRange)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
constexpr char kFS[] = R"(#version 300 es
precision highp int;
precision highp float;
uniform uint u;
uniform uint big;
out vec4 color;
void main() {
uint r0 = u << big;
uint r1 = u >> big;
uint r2 = u << 31u;
uint r3 = u >> 31u;
color.r = r0 == 4294967295u ? 1.0 : 0.0;
color.g = r1 == 4294967295u ? 1.0 : 0.0;
color.b = r2 == 2147483648u ? 1.0 : 0.0;
color.a = r3 == 1u ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint big = glGetUniformLocation(testProgram, "big");
EXPECT_NE(-1, big);
glUniform1ui(u, 4294967295u);
glUniform1ui(big, 32u);
drawQuad(testProgram, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test int <<= int and int >>= int with a shift amount that is out of range.
TEST_P(GLSLUBTest, ShiftAssignIntAmountOutOfRange)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
constexpr char kFS[] = R"(#version 300 es
precision highp int;
precision highp float;
uniform int u;
uniform int big;
out vec4 color;
void main() {
int r0 = u;
r0 <<= big;
int r1 = u;
r1 >>= big;
int r2 = u;
r2 <<= 1;
int r3 = u;
r3 >>= 1;
color.r = r0 == -8 ? 1.0 : 0.0;
color.g = r1 == -8 ? 1.0 : 0.0;
color.b = r2 == -16 ? 1.0 : 0.0;
color.a = r3 == -4 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint big = glGetUniformLocation(testProgram, "big");
EXPECT_NE(-1, big);
glUniform1i(u, -8);
glUniform1i(big, 32);
drawQuad(testProgram, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test ivec << ivec, ivec << int and ivec <<= int with shift amounts that are out of range.
TEST_P(GLSLUBTest, ShiftLeftIvecAmountOutOfRange)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
constexpr char kFS[] = R"(#version 300 es
precision highp int;
precision highp float;
uniform ivec4 u;
uniform ivec4 amounts;
uniform int big;
out vec4 color;
void main() {
ivec4 r0 = u << amounts;
ivec4 r1 = u << big;
ivec4 r2 = u;
r2 <<= big;
color.r = r0 == ivec4(1, 2, 1, -2147483648) ? 1.0 : 0.0;
color.g = r1 == ivec4(1) ? 1.0 : 0.0;
color.b = r2 == ivec4(1) ? 1.0 : 0.0;
color.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint amounts = glGetUniformLocation(testProgram, "amounts");
EXPECT_NE(-1, amounts);
GLint big = glGetUniformLocation(testProgram, "big");
EXPECT_NE(-1, big);
glUniform4i(u, 1, 1, 1, 1);
glUniform4i(amounts, 0, 1, 32, -1);
glUniform1i(big, 64);
drawQuad(testProgram, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test float to int conversion where the value is out of range. GLSL ES 3.00 section 5.4.1 only
// specifies that the fractional part is dropped and does not define a result for values that are
// not representable, so the values asserted here are what the emulation produces: it clamps to the
// representable range.
TEST_P(GLSLUBTest, FloatToIntOutOfRange)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform float hi;
uniform float lo;
void main() {
int r0 = int(hi);
int r1 = int(lo);
int r2 = int(2.7);
int r3 = int(-2.7);
gl_FragColor.r = r0 == 2147483520 ? 1.0 : 0.0;
gl_FragColor.g = r1 == -2147483648 ? 1.0 : 0.0;
gl_FragColor.b = r2 == 2 ? 1.0 : 0.0;
gl_FragColor.a = r3 == -2 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint hi = glGetUniformLocation(testProgram, "hi");
EXPECT_NE(-1, hi);
GLint lo = glGetUniformLocation(testProgram, "lo");
EXPECT_NE(-1, lo);
glUniform1f(hi, 1.0e10f);
glUniform1f(lo, -1.0e10f);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test float to int conversion of the values at the edges of the int range. Unlike the out of range
// cases, these are representable, so GLSL ES 3.00 section 5.4.1 requires the exact values and the
// clamping must not perturb them.
TEST_P(GLSLUBTest, FloatToIntInRange)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform float hi;
uniform float lo;
void main() {
int r0 = int(hi);
int r1 = int(lo);
gl_FragColor.r = r0 == 2147483520 ? 1.0 : 0.0;
gl_FragColor.g = r1 == -2147483648 ? 1.0 : 0.0;
gl_FragColor.b = 1.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint hi = glGetUniformLocation(testProgram, "hi");
EXPECT_NE(-1, hi);
GLint lo = glGetUniformLocation(testProgram, "lo");
EXPECT_NE(-1, lo);
// The largest float that is smaller than 2^31, and -2^31.
glUniform1f(hi, 2147483520.0f);
glUniform1f(lo, -2147483648.0f);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test float to uint conversion where the value is out of range. Note that GLSL ES 3.00 section
// 5.4.1 does explicitly make conversion of a negative value to uint undefined.
TEST_P(GLSLUBTest, FloatToUintOutOfRange)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
constexpr char kFS[] = R"(#version 300 es
precision highp int;
precision highp float;
uniform float hi;
uniform float lo;
out vec4 color;
void main() {
uint r0 = uint(hi);
uint r1 = uint(lo);
uint r2 = uint(2.7);
uvec2 r3 = uvec2(vec2(hi, lo));
color.r = r0 == 4294967040u ? 1.0 : 0.0;
color.g = r1 == 0u ? 1.0 : 0.0;
color.b = r2 == 2u ? 1.0 : 0.0;
color.a = r3 == uvec2(4294967040u, 0u) ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint hi = glGetUniformLocation(testProgram, "hi");
EXPECT_NE(-1, hi);
GLint lo = glGetUniformLocation(testProgram, "lo");
EXPECT_NE(-1, lo);
glUniform1f(hi, 1.0e10f);
glUniform1f(lo, -1.0e10f);
drawQuad(testProgram, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test vec4 to ivec4 conversion where the values are out of range. The asserted values are what
// the emulation clamps to, see FloatToIntOutOfRange.
TEST_P(GLSLUBTest, FloatToIvecOutOfRange)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform vec4 u;
void main() {
ivec4 r = ivec4(u);
gl_FragColor.r = r.x == 2147483520 ? 1.0 : 0.0;
gl_FragColor.g = r.y == -2147483648 ? 1.0 : 0.0;
gl_FragColor.b = r.z == 2 ? 1.0 : 0.0;
gl_FragColor.a = r.w == -2 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform4f(u, 1.0e10f, -1.0e10f, 2.7f, -2.7f);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test a multi argument ivec constructor where the values are out of range. These are split into
// per component conversions before being emitted. The asserted values are what the emulation clamps
// to, see FloatToIntOutOfRange.
TEST_P(GLSLUBTest, FloatToIvecMultiArgumentOutOfRange)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform float a;
uniform float b;
uniform vec2 v;
void main() {
ivec2 r0 = ivec2(a, b);
ivec4 r1 = ivec4(v, v);
ivec3 r2 = ivec3(a, v);
gl_FragColor.r = r0 == ivec2(2147483520, -2147483648) ? 1.0 : 0.0;
gl_FragColor.g = r1 == ivec4(2147483520, -2147483648, 2147483520, -2147483648) ? 1.0 : 0.0;
gl_FragColor.b = r2 == ivec3(2147483520, 2147483520, -2147483648) ? 1.0 : 0.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint a = glGetUniformLocation(testProgram, "a");
EXPECT_NE(-1, a);
GLint b = glGetUniformLocation(testProgram, "b");
EXPECT_NE(-1, b);
GLint v = glGetUniformLocation(testProgram, "v");
EXPECT_NE(-1, v);
glUniform1f(a, 1.0e10f);
glUniform1f(b, -1.0e10f);
glUniform2f(v, 1.0e10f, -1.0e10f);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test ++ and -- on a vector element with a dynamic index. Expect wraparound. The operand of the
// emulated operators has to be addressable.
TEST_P(GLSLUBTest, IncrementIvecElementOverflow)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
constexpr char kFS[] = R"(#version 300 es
precision highp int;
precision highp float;
uniform ivec4 u;
uniform int i;
out vec4 color;
void main() {
ivec4 r0 = u;
r0[i]++;
ivec4 r1 = u;
++r1[i];
ivec4 r2 = u;
r2[i + 1]--;
ivec4 r3 = u;
--r3[i + 1];
color.r = r0 == ivec4(0, 1, -2147483648, -2147483648) ? 1.0 : 0.0;
color.g = r0 == r1 ? 1.0 : 0.0;
color.b = r2 == ivec4(0, 1, 2147483647, 2147483647) ? 1.0 : 0.0;
color.a = r2 == r3 ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint i = glGetUniformLocation(testProgram, "i");
EXPECT_NE(-1, i);
glUniform4i(u, 0, 1, 2147483647, -2147483647 - 1);
glUniform1i(i, 2);
drawQuad(testProgram, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test ++ and -- on a swizzle. Expect wraparound. The operand of the emulated operators has to be
// addressable.
TEST_P(GLSLUBTest, IncrementIvecSwizzleOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform ivec4 u;
void main() {
ivec4 r0 = u;
r0.z++;
ivec4 r1 = u;
r1.zw--;
ivec4 r2 = u;
--r2.wz;
gl_FragColor.r = r0 == ivec4(0, 1, -2147483648, -2147483648) ? 1.0 : 0.0;
gl_FragColor.g = r1 == ivec4(0, 1, 2147483646, 2147483647) ? 1.0 : 0.0;
gl_FragColor.b = r1 == r2 ? 1.0 : 0.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform4i(u, 0, 1, 2147483647, -2147483647 - 1);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test compound assignment to a vector element and to a swizzle. Expect wraparound.
TEST_P(GLSLUBTest, AssignIvecElementOverflow)
{
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
constexpr char kFS[] = R"(#version 300 es
precision highp int;
precision highp float;
uniform ivec4 u;
uniform int i;
out vec4 color;
void main() {
ivec4 r0 = u;
r0[i] += 2;
ivec4 r1 = u;
r1.z -= -2;
ivec4 r2 = u;
r2.zw *= 2;
ivec4 r3 = u;
r3[i] <<= 33;
color.r = r0 == ivec4(0, 1, -2147483647, -2147483648) ? 1.0 : 0.0;
color.g = r0 == r1 ? 1.0 : 0.0;
color.b = r2 == ivec4(0, 1, -2, 0) ? 1.0 : 0.0;
// The shift amount is masked, so shifting by 33 shifts by 1.
color.a = r3 == ivec4(0, 1, -2, -2147483648) ? 1.0 : 0.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl3_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
GLint i = glGetUniformLocation(testProgram, "i");
EXPECT_NE(-1, i);
glUniform4i(u, 0, 1, 2147483647, -2147483647 - 1);
glUniform1i(i, 2);
drawQuad(testProgram, essl3_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
// Test that the emulated operators work on function out and inout arguments.
TEST_P(GLSLUBTest, OutArgumentOverflow)
{
constexpr char kFS[] = R"(
precision highp int;
precision highp float;
uniform int u;
void addOne(inout int x) { x++; }
void mulTwo(inout ivec2 x) { x *= 2; }
void main() {
int r0 = u;
addOne(r0);
ivec4 r1 = ivec4(u, u, 1, 2);
addOne(r1[2]);
ivec4 r2 = ivec4(u, u, 1, 2);
mulTwo(r2.xy);
gl_FragColor.r = r0 == -2147483648 ? 1.0 : 0.0;
gl_FragColor.g = r1 == ivec4(2147483647, 2147483647, 2, 2) ? 1.0 : 0.0;
gl_FragColor.b = r2 == ivec4(-2, -2, 1, 2) ? 1.0 : 0.0;
gl_FragColor.a = 1.0;
}
)";
ANGLE_GL_PROGRAM(testProgram, essl1_shaders::vs::Simple(), kFS);
ASSERT_GL_NO_ERROR();
glUseProgram(testProgram);
GLint u = glGetUniformLocation(testProgram, "u");
EXPECT_NE(-1, u);
glUniform1i(u, 2147483647);
drawQuad(testProgram, essl1_shaders::PositionAttrib(), 0.5f, 1.0f, true);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(255, 255, 255, 255));
ASSERT_GL_NO_ERROR();
}
} // anonymous namespace
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GLSLUBTest);
ANGLE_INSTANTIATE_TEST(GLSLUBTest, ES2_METAL(), ES3_METAL());