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)
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,
Program *program)
{
const State &state = context->getState();
if (extensions.multiview || extensions.multiview2)
{
const int programNumViews = program->usesMultiview() ? program->getNumViews() : 1;
......@@ -574,14 +575,15 @@ ANGLE_INLINE const char *ValidateProgramDrawStates(const State &state,
const OffsetBindingPointer<Buffer> &uniformBuffer =
state.getIndexedUniformBuffer(blockBinding);
if (uniformBuffer.get() == nullptr)
if (uniformBuffer.get() == nullptr && context->isWebGL())
{
// undefined behaviour
return gl::err::kUniformBufferUnbound;
}
size_t uniformBufferSize = GetBoundBufferAvailableSize(uniformBuffer);
if (uniformBufferSize < uniformBlock.dataSize)
if (uniformBufferSize < uniformBlock.dataSize &&
(context->isWebGL() || context->isBufferAccessValidationEnabled()))
{
// undefined behaviour
return gl::err::kUniformBufferTooSmall;
......@@ -3616,7 +3618,7 @@ bool ValidateCopyTexImageParametersBase(const Context *context,
return true;
}
const char *ValidateProgramPipelineDrawStates(const State &state,
const char *ValidateProgramPipelineDrawStates(const Context *context,
const Extensions &extensions,
ProgramPipeline *programPipeline)
{
......@@ -3625,7 +3627,7 @@ const char *ValidateProgramPipelineDrawStates(const State &state,
Program *program = programPipeline->getShaderProgram(shaderType);
if (program)
{
const char *errorMsg = ValidateProgramDrawStates(state, extensions, program);
const char *errorMsg = ValidateProgramDrawStates(context, extensions, program);
if (errorMsg)
{
return errorMsg;
......@@ -3818,7 +3820,7 @@ const char *ValidateDrawStates(const Context *context)
if (program)
{
const char *errorMsg = ValidateProgramDrawStates(state, extensions, program);
const char *errorMsg = ValidateProgramDrawStates(context, extensions, program);
if (errorMsg)
{
return errorMsg;
......@@ -3834,7 +3836,7 @@ const char *ValidateDrawStates(const Context *context)
return errorMsg;
}
errorMsg = ValidateProgramPipelineDrawStates(state, extensions, programPipeline);
errorMsg = ValidateProgramPipelineDrawStates(context, extensions, programPipeline);
if (errorMsg)
{
return errorMsg;
......
......@@ -5213,7 +5213,7 @@ TEST_P(WebGLComputeValidationStateChangeTest, DrawPastEndOfBufferWithDivisor)
}
// Tests state changes with uniform block validation.
TEST_P(ValidationStateChangeTest, UniformBlockNegativeAPI)
TEST_P(WebGL2ValidationStateChangeTest, UniformBlockNegativeAPI)
{
constexpr char kVS[] = R"(#version 300 es
in vec2 position;
......
......@@ -192,18 +192,6 @@ TEST_P(UniformBufferTest, UniformBufferBindings)
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.
// https://code.google.com/p/angleproject/issues/detail?id=965
TEST_P(UniformBufferTest, UniformBufferManyUpdates)
......@@ -1678,45 +1666,6 @@ TEST_P(UniformBufferTest, SizeOverMaxBlockSize)
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_P(UniformBufferTest, Std140UniformBlockWithDynamicallyIndexedRowMajorArray)
{
......@@ -3389,6 +3338,63 @@ void main() {
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);
ANGLE_INSTANTIATE_TEST_ES3(UniformBufferTest);
......@@ -3398,4 +3404,7 @@ ANGLE_INSTANTIATE_TEST_ES3(UniformBlockWithOneLargeArrayMemberTest);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UniformBufferTest31);
ANGLE_INSTANTIATE_TEST_ES31(UniformBufferTest31);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WebGL2UniformBufferTest);
ANGLE_INSTANTIATE_TEST_ES3(WebGL2UniformBufferTest);
} // 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