Commit 5d314b59 by Trevor David Black Committed by Angle LUCI CQ

Fix undefined behavior associated with Runescape Mobile

Bug: b/184287970 Change-Id: I5d3baf5e7a8a20c30e1b787b69597110226521d8 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2929352Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 37c5d36f
...@@ -538,10 +538,11 @@ unsigned int GetSamplerParameterCount(GLenum pname) ...@@ -538,10 +538,11 @@ unsigned int GetSamplerParameterCount(GLenum pname)
return pname == GL_TEXTURE_BORDER_COLOR ? 4 : 1; return pname == GL_TEXTURE_BORDER_COLOR ? 4 : 1;
} }
ANGLE_INLINE const char *ValidateProgramDrawStates(const State &state, ANGLE_INLINE const char *ValidateProgramDrawStates(const Context *context,
const Extensions &extensions, const Extensions &extensions,
Program *program) Program *program)
{ {
const State &state = context->getState();
if (extensions.multiview || extensions.multiview2) if (extensions.multiview || extensions.multiview2)
{ {
const int programNumViews = program->usesMultiview() ? program->getNumViews() : 1; const int programNumViews = program->usesMultiview() ? program->getNumViews() : 1;
...@@ -574,14 +575,15 @@ ANGLE_INLINE const char *ValidateProgramDrawStates(const State &state, ...@@ -574,14 +575,15 @@ ANGLE_INLINE const char *ValidateProgramDrawStates(const State &state,
const OffsetBindingPointer<Buffer> &uniformBuffer = const OffsetBindingPointer<Buffer> &uniformBuffer =
state.getIndexedUniformBuffer(blockBinding); state.getIndexedUniformBuffer(blockBinding);
if (uniformBuffer.get() == nullptr) if (uniformBuffer.get() == nullptr && context->isWebGL())
{ {
// undefined behaviour // undefined behaviour
return gl::err::kUniformBufferUnbound; return gl::err::kUniformBufferUnbound;
} }
size_t uniformBufferSize = GetBoundBufferAvailableSize(uniformBuffer); size_t uniformBufferSize = GetBoundBufferAvailableSize(uniformBuffer);
if (uniformBufferSize < uniformBlock.dataSize) if (uniformBufferSize < uniformBlock.dataSize &&
(context->isWebGL() || context->isBufferAccessValidationEnabled()))
{ {
// undefined behaviour // undefined behaviour
return gl::err::kUniformBufferTooSmall; return gl::err::kUniformBufferTooSmall;
...@@ -3616,7 +3618,7 @@ bool ValidateCopyTexImageParametersBase(const Context *context, ...@@ -3616,7 +3618,7 @@ bool ValidateCopyTexImageParametersBase(const Context *context,
return true; return true;
} }
const char *ValidateProgramPipelineDrawStates(const State &state, const char *ValidateProgramPipelineDrawStates(const Context *context,
const Extensions &extensions, const Extensions &extensions,
ProgramPipeline *programPipeline) ProgramPipeline *programPipeline)
{ {
...@@ -3625,7 +3627,7 @@ const char *ValidateProgramPipelineDrawStates(const State &state, ...@@ -3625,7 +3627,7 @@ const char *ValidateProgramPipelineDrawStates(const State &state,
Program *program = programPipeline->getShaderProgram(shaderType); Program *program = programPipeline->getShaderProgram(shaderType);
if (program) if (program)
{ {
const char *errorMsg = ValidateProgramDrawStates(state, extensions, program); const char *errorMsg = ValidateProgramDrawStates(context, extensions, program);
if (errorMsg) if (errorMsg)
{ {
return errorMsg; return errorMsg;
...@@ -3818,7 +3820,7 @@ const char *ValidateDrawStates(const Context *context) ...@@ -3818,7 +3820,7 @@ const char *ValidateDrawStates(const Context *context)
if (program) if (program)
{ {
const char *errorMsg = ValidateProgramDrawStates(state, extensions, program); const char *errorMsg = ValidateProgramDrawStates(context, extensions, program);
if (errorMsg) if (errorMsg)
{ {
return errorMsg; return errorMsg;
...@@ -3834,7 +3836,7 @@ const char *ValidateDrawStates(const Context *context) ...@@ -3834,7 +3836,7 @@ const char *ValidateDrawStates(const Context *context)
return errorMsg; return errorMsg;
} }
errorMsg = ValidateProgramPipelineDrawStates(state, extensions, programPipeline); errorMsg = ValidateProgramPipelineDrawStates(context, extensions, programPipeline);
if (errorMsg) if (errorMsg)
{ {
return errorMsg; return errorMsg;
......
...@@ -5213,7 +5213,7 @@ TEST_P(WebGLComputeValidationStateChangeTest, DrawPastEndOfBufferWithDivisor) ...@@ -5213,7 +5213,7 @@ TEST_P(WebGLComputeValidationStateChangeTest, DrawPastEndOfBufferWithDivisor)
} }
// Tests state changes with uniform block validation. // Tests state changes with uniform block validation.
TEST_P(ValidationStateChangeTest, UniformBlockNegativeAPI) TEST_P(WebGL2ValidationStateChangeTest, UniformBlockNegativeAPI)
{ {
constexpr char kVS[] = R"(#version 300 es constexpr char kVS[] = R"(#version 300 es
in vec2 position; in vec2 position;
......
...@@ -192,18 +192,6 @@ TEST_P(UniformBufferTest, UniformBufferBindings) ...@@ -192,18 +192,6 @@ TEST_P(UniformBufferTest, UniformBufferBindings)
EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40); EXPECT_PIXEL_EQ(px, py, 10, 20, 30, 40);
} }
// Test that ANGLE handles used but unbound UBO. Assumes we are running on ANGLE and produce
// optional but not mandatory errors.
TEST_P(UniformBufferTest, ANGLEUnboundUniformBuffer)
{
glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, 0);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
// Update a UBO many time and verify that ANGLE uses the latest version of the data. // Update a UBO many time and verify that ANGLE uses the latest version of the data.
// https://code.google.com/p/angleproject/issues/detail?id=965 // https://code.google.com/p/angleproject/issues/detail?id=965
TEST_P(UniformBufferTest, UniformBufferManyUpdates) TEST_P(UniformBufferTest, UniformBufferManyUpdates)
...@@ -1678,45 +1666,6 @@ TEST_P(UniformBufferTest, SizeOverMaxBlockSize) ...@@ -1678,45 +1666,6 @@ TEST_P(UniformBufferTest, SizeOverMaxBlockSize)
EXPECT_PIXEL_COLOR_EQ(width / 2 + 5, height / 2 + 5, GLColor::green); EXPECT_PIXEL_COLOR_EQ(width / 2 + 5, height / 2 + 5, GLColor::green);
} }
// Compile uniform buffer with large array member.
TEST_P(UniformBufferTest, LargeArrayOfStructs)
{
constexpr char kVertexShader[] = R"(
struct InstancingData
{
mat4 transformation;
};
layout(std140) uniform InstanceBlock
{
InstancingData instances[MAX_INSTANCE_COUNT];
};
void main()
{
gl_Position = vec4(1.0) * instances[gl_InstanceID].transformation;
})";
constexpr char kFragmentShader[] = R"(#version 300 es
precision mediump float;
out vec4 outFragColor;
void main()
{
outFragColor = vec4(0.0);
})";
int maxUniformBlockSize;
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
std::string vs = "#version 300 es\n#define MAX_INSTANCE_COUNT " +
std::to_string(std::min(800, maxUniformBlockSize / 64)) + kVertexShader;
ANGLE_GL_PROGRAM(program, vs.c_str(), kFragmentShader);
// Add a draw call for the sake of the Vulkan backend that currently really builds shaders at
// draw time.
drawQuad(program.get(), essl3_shaders::PositionAttrib(), 0.5f);
}
// Test a uniform block where an array of row-major matrices is dynamically indexed. // Test a uniform block where an array of row-major matrices is dynamically indexed.
TEST_P(UniformBufferTest, Std140UniformBlockWithDynamicallyIndexedRowMajorArray) TEST_P(UniformBufferTest, Std140UniformBlockWithDynamicallyIndexedRowMajorArray)
{ {
...@@ -3389,6 +3338,63 @@ void main() { ...@@ -3389,6 +3338,63 @@ void main() {
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
} }
class WebGL2UniformBufferTest : public UniformBufferTest
{
protected:
WebGL2UniformBufferTest() { setWebGLCompatibilityEnabled(true); }
};
// Test that ANGLE handles used but unbound UBO. Assumes we are running on ANGLE and produce
// optional but not mandatory errors.
TEST_P(WebGL2UniformBufferTest, ANGLEUnboundUniformBuffer)
{
glUniformBlockBinding(mProgram, mUniformBufferIndex, 0);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, 0);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, essl3_shaders::PositionAttrib(), 0.5f);
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
// Compile uniform buffer with large array member.
TEST_P(WebGL2UniformBufferTest, LargeArrayOfStructs)
{
constexpr char kVertexShader[] = R"(
struct InstancingData
{
mat4 transformation;
};
layout(std140) uniform InstanceBlock
{
InstancingData instances[MAX_INSTANCE_COUNT];
};
void main()
{
gl_Position = vec4(1.0) * instances[gl_InstanceID].transformation;
})";
constexpr char kFragmentShader[] = R"(#version 300 es
precision mediump float;
out vec4 outFragColor;
void main()
{
outFragColor = vec4(0.0);
})";
int maxUniformBlockSize;
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
std::string vs = "#version 300 es\n#define MAX_INSTANCE_COUNT " +
std::to_string(std::min(800, maxUniformBlockSize / 64)) + kVertexShader;
ANGLE_GL_PROGRAM(program, vs.c_str(), kFragmentShader);
// Add a draw call for the sake of the Vulkan backend that currently really builds shaders at
// draw time.
drawQuad(program.get(), essl3_shaders::PositionAttrib(), 0.5f);
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UniformBufferTest); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UniformBufferTest);
ANGLE_INSTANTIATE_TEST_ES3(UniformBufferTest); ANGLE_INSTANTIATE_TEST_ES3(UniformBufferTest);
...@@ -3398,4 +3404,7 @@ ANGLE_INSTANTIATE_TEST_ES3(UniformBlockWithOneLargeArrayMemberTest); ...@@ -3398,4 +3404,7 @@ ANGLE_INSTANTIATE_TEST_ES3(UniformBlockWithOneLargeArrayMemberTest);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UniformBufferTest31); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UniformBufferTest31);
ANGLE_INSTANTIATE_TEST_ES31(UniformBufferTest31); ANGLE_INSTANTIATE_TEST_ES31(UniformBufferTest31);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WebGL2UniformBufferTest);
ANGLE_INSTANTIATE_TEST_ES3(WebGL2UniformBufferTest);
} // namespace } // namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment