blob: a53ba6fd09fd3e6cfa967464f1342132e6832438 [file] [log] [blame] [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/gl_raii.h"
#include "util/shader_utils.h"
namespace
{
// To inspect current behavior, run the tests in following manner:
// clang-format off
// ANGLE_FEATURE_OVERRIDES_DISABLED=injectAsmStatementIntoLoopBodies GMD_STDOUT=1 ./out/Debug/angle_end2end_tests --gtest_also_run_disabled_tests --gtest_filter=TimeoutDrawTest.DISABLED_DynamicInfiniteLoop2VS/ES3_Metal
// GMD_STDOUT=1 ./out/Debug/angle_end2end_tests --gtest_also_run_disabled_tests --gtest_filter=TimeoutDrawTest.DISABLED_DynamicInfiniteLoop2VS/ES3_Metal_EnsureLoopForwardProgress
// clang-format on
using namespace angle;
class TimeoutDrawTest : public ANGLETest<>
{
protected:
TimeoutDrawTest()
{
setWindowWidth(128);
setWindowHeight(128);
setConfigRedBits(8);
setConfigGreenBits(8);
setConfigBlueBits(8);
setConfigAlphaBits(8);
// Tests should skip if robustness not supported, but this can be done only after
// Metal supports robustness.
if (IsEGLClientExtensionEnabled("EGL_EXT_create_context_robustness"))
{
setContextResetStrategy(EGL_LOSE_CONTEXT_ON_RESET_EXT);
}
else
{
setContextResetStrategy(EGL_NO_RESET_NOTIFICATION_EXT);
}
}
void testSetUp() override
{
glClear(GL_COLOR_BUFFER_BIT);
glFinish();
}
};
// Tests that trivial infinite loops in vertex shaders hang instead of progress.
TEST_P(TimeoutDrawTest, DISABLED_TrivialInfiniteLoopVS)
{
constexpr char kVS[] = R"(precision highp float;
attribute vec4 a_position;
void main()
{
for (;;) {}
gl_Position = a_position;
})";
ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
glFinish();
if (glGetError() != GL_CONTEXT_LOST)
{
FAIL();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
}
}
// Tests that trivial infinite loops in fragment shaders hang instead of progress.
TEST_P(TimeoutDrawTest, DISABLED_TrivialInfiniteLoopFS)
{
constexpr char kFS[] = R"(precision mediump float;
void main()
{
for (;;) {}
gl_FragColor = vec4(1, 0, 0, 1);
})";
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
glFinish();
if (glGetError() != GL_CONTEXT_LOST)
{
FAIL();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
}
}
// Tests that infinite loops based on user-supplied values in vertex shaders hang instead of
// progress. Otherwise optimizer would be able to assume something about the domain of the
// user-supplied value.
TEST_P(TimeoutDrawTest, DISABLED_DynamicInfiniteLoopVS)
{
constexpr char kVS[] = R"(precision highp float;
attribute vec4 a_position;
uniform int f;
void main()
{
for (;f != 0;) {}
gl_Position = a_position;
})";
ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
glUseProgram(program);
GLint uniformLocation = glGetUniformLocation(program, "f");
glUniform1i(uniformLocation, 77);
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
glFinish();
if (glGetError() != GL_CONTEXT_LOST)
{
FAIL();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
}
}
// Tests that infinite loops based on user-supplied values in fragment shaders hang instead of
// progress. Otherwise optimizer would be able to assume something about the domain of the
// user-supplied value.
TEST_P(TimeoutDrawTest, DISABLED_DynamicInfiniteLoopFS)
{
constexpr char kFS[] = R"(precision mediump float;
uniform int f;
void main()
{
for (;f != 0;) {}
gl_FragColor = vec4(1, 0, 0, 1);
})";
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS);
glUseProgram(program);
GLint uniformLocation = glGetUniformLocation(program, "f");
glUniform1i(uniformLocation, 88);
EXPECT_GL_NO_ERROR();
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
glFinish();
if (glGetError() != GL_CONTEXT_LOST)
{
FAIL();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
}
}
// Tests that infinite loops based on user-supplied values in vertex shaders hang instead of
// progress. Otherwise optimizer would be able to assume something about the domain of the
// user-supplied value. Explicit value break variant.
TEST_P(TimeoutDrawTest, DISABLED_DynamicInfiniteLoop2VS)
{
constexpr char kVS[] = R"(precision highp float;
attribute vec4 a_position;
uniform int f;
void main()
{
for (;;) { if (f <= 1) break; }
gl_Position = a_position;
})";
ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Red());
glUseProgram(program);
GLint uniformLocation = glGetUniformLocation(program, "f");
glUniform1i(uniformLocation, 66);
EXPECT_GL_NO_ERROR();
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
glFinish();
if (glGetError() != GL_CONTEXT_LOST)
{
FAIL();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
}
}
// Tests that infinite loops based on user-supplied values in fragment shaders hang instead of
// progress. Otherwise optimizer would be able to assume something about the domain of the
// user-supplied value. Explicit value break variant.
TEST_P(TimeoutDrawTest, DISABLED_DynamicInfiniteLoop2FS)
{
constexpr char kFS[] = R"(precision mediump float;
uniform float f;
void main()
{
for (;;) { if (f < 0.1) break; }
gl_FragColor = vec4(1, 0, f, 1);
})";
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS);
glUseProgram(program);
GLint uniformLocation = glGetUniformLocation(program, "f");
glUniform1f(uniformLocation, .5f);
EXPECT_GL_NO_ERROR();
drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
glFinish();
if (glGetError() != GL_CONTEXT_LOST)
{
FAIL();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
}
}
} // namespace
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TimeoutDrawTest);
ANGLE_INSTANTIATE_TEST(
TimeoutDrawTest,
WithRobustness(ES2_METAL()),
WithRobustness(ES3_METAL()),
WithRobustness(ES2_METAL().enable(Feature::InjectAsmStatementIntoLoopBodies)),
WithRobustness(ES3_METAL().enable(Feature::InjectAsmStatementIntoLoopBodies)),
WithRobustness(ES2_METAL().enable(Feature::EnsureLoopForwardProgress)),
WithRobustness(ES3_METAL().enable(Feature::EnsureLoopForwardProgress)));