Commit 3f01f53c by Qin Jiajia Committed by Commit Bot

ES31: Add state change tests for image

This change adds dirty bit state change tests for image textures. Meanwhile, syncImages related codes are removed since syncTextures will do all texture states sync. Bug: angleproject:3015 Change-Id: I9b299c86af1d589e72c08c5d7c55ac74cc7833aa Reviewed-on: https://chromium-review.googlesource.com/c/1390596 Commit-Queue: Jiajia Qin <jiajia.qin@intel.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent cb9609fe
...@@ -284,9 +284,7 @@ enum SubjectIndexes : angle::SubjectIndex ...@@ -284,9 +284,7 @@ enum SubjectIndexes : angle::SubjectIndex
{ {
kTexture0SubjectIndex = 0, kTexture0SubjectIndex = 0,
kTextureMaxSubjectIndex = kTexture0SubjectIndex + IMPLEMENTATION_MAX_ACTIVE_TEXTURES, kTextureMaxSubjectIndex = kTexture0SubjectIndex + IMPLEMENTATION_MAX_ACTIVE_TEXTURES,
kImage0SubjectIndex = kTextureMaxSubjectIndex, kUniformBuffer0SubjectIndex = kTextureMaxSubjectIndex,
kImageMaxSubjectIndex = kImage0SubjectIndex + IMPLEMENTATION_MAX_IMAGE_UNITS,
kUniformBuffer0SubjectIndex = kImageMaxSubjectIndex,
kUniformBufferMaxSubjectIndex = kUniformBufferMaxSubjectIndex =
kUniformBuffer0SubjectIndex + IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS, kUniformBuffer0SubjectIndex + IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS,
kSampler0SubjectIndex = kUniformBufferMaxSubjectIndex, kSampler0SubjectIndex = kUniformBufferMaxSubjectIndex,
...@@ -358,12 +356,6 @@ Context::Context(rx::EGLImplFactory *implFactory, ...@@ -358,12 +356,6 @@ Context::Context(rx::EGLImplFactory *implFactory,
{ {
mSamplerObserverBindings.emplace_back(this, samplerIndex); mSamplerObserverBindings.emplace_back(this, samplerIndex);
} }
for (angle::SubjectIndex imageIndex = kImage0SubjectIndex; imageIndex < kImageMaxSubjectIndex;
++imageIndex)
{
mImageObserverBindings.emplace_back(this, imageIndex);
}
} }
void Context::initialize() void Context::initialize()
...@@ -1155,7 +1147,6 @@ void Context::bindImageTexture(GLuint unit, ...@@ -1155,7 +1147,6 @@ void Context::bindImageTexture(GLuint unit,
{ {
Texture *tex = mState.mTextures->getTexture(texture); Texture *tex = mState.mTextures->getTexture(texture);
mGLState.setImageUnit(this, unit, tex, level, layered, layer, access, format); mGLState.setImageUnit(this, unit, tex, level, layered, layer, access, format);
mImageObserverBindings[unit].bind(tex);
} }
void Context::useProgram(GLuint program) void Context::useProgram(GLuint program)
...@@ -8062,10 +8053,6 @@ void Context::onSubjectStateChange(const Context *context, ...@@ -8062,10 +8053,6 @@ void Context::onSubjectStateChange(const Context *context,
mGLState.onActiveTextureStateChange(this, index); mGLState.onActiveTextureStateChange(this, index);
mStateCache.onActiveTextureChange(this); mStateCache.onActiveTextureChange(this);
} }
else if (index < kImageMaxSubjectIndex)
{
mGLState.onImageStateChange(this, index - kImage0SubjectIndex);
}
else if (index < kUniformBufferMaxSubjectIndex) else if (index < kUniformBufferMaxSubjectIndex)
{ {
mGLState.onUniformBufferStateChange(index - kUniformBuffer0SubjectIndex); mGLState.onUniformBufferStateChange(index - kUniformBuffer0SubjectIndex);
......
...@@ -1904,7 +1904,6 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl ...@@ -1904,7 +1904,6 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
angle::ObserverBinding mReadFramebufferObserverBinding; angle::ObserverBinding mReadFramebufferObserverBinding;
std::vector<angle::ObserverBinding> mUniformBufferObserverBindings; std::vector<angle::ObserverBinding> mUniformBufferObserverBindings;
std::vector<angle::ObserverBinding> mSamplerObserverBindings; std::vector<angle::ObserverBinding> mSamplerObserverBindings;
std::vector<angle::ObserverBinding> mImageObserverBindings;
// Not really a property of context state. The size and contexts change per-api-call. // Not really a property of context state. The size and contexts change per-api-call.
mutable angle::ScratchBuffer mScratchBuffer; mutable angle::ScratchBuffer mScratchBuffer;
......
...@@ -2532,23 +2532,6 @@ angle::Result State::syncTextures(const Context *context) ...@@ -2532,23 +2532,6 @@ angle::Result State::syncTextures(const Context *context)
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result State::syncImages(const Context *context)
{
if (mDirtyImages.none())
return angle::Result::Continue;
for (size_t imageUnitIndex : mDirtyImages)
{
Texture *texture = mImageUnits[imageUnitIndex].texture.get();
if (texture && texture->hasAnyDirtyBit())
{
ANGLE_TRY(texture->syncState(context));
}
}
return angle::Result::Continue;
}
angle::Result State::syncSamplers(const Context *context) angle::Result State::syncSamplers(const Context *context)
{ {
if (mDirtySamplers.none()) if (mDirtySamplers.none())
...@@ -2785,11 +2768,6 @@ void State::onImageStateChange(const Context *context, size_t unit) ...@@ -2785,11 +2768,6 @@ void State::onImageStateChange(const Context *context, size_t unit)
{ {
const ImageUnit &image = mImageUnits[unit]; const ImageUnit &image = mImageUnits[unit];
ASSERT(image.texture.get()); ASSERT(image.texture.get());
if (image.texture->hasAnyDirtyBit())
{
mDirtyImages.set(unit);
}
if (mRobustResourceInit && image.texture->initState() == InitState::MayNeedInit) if (mRobustResourceInit && image.texture->initState() == InitState::MayNeedInit)
{ {
mDirtyObjects.set(DIRTY_OBJECT_IMAGES_INIT); mDirtyObjects.set(DIRTY_OBJECT_IMAGES_INIT);
......
...@@ -488,7 +488,6 @@ class State : angle::NonCopyable ...@@ -488,7 +488,6 @@ class State : angle::NonCopyable
DIRTY_OBJECT_DRAW_ATTACHMENTS, DIRTY_OBJECT_DRAW_ATTACHMENTS,
DIRTY_OBJECT_VERTEX_ARRAY, DIRTY_OBJECT_VERTEX_ARRAY,
DIRTY_OBJECT_TEXTURES, // Top-level dirty bit. Also see mDirtyTextures. DIRTY_OBJECT_TEXTURES, // Top-level dirty bit. Also see mDirtyTextures.
DIRTY_OBJECT_IMAGES, // Top-level dirty bit. Also see mDirtyImages.
DIRTY_OBJECT_SAMPLERS, // Top-level dirty bit. Also see mDirtySamplers. DIRTY_OBJECT_SAMPLERS, // Top-level dirty bit. Also see mDirtySamplers.
DIRTY_OBJECT_PROGRAM, DIRTY_OBJECT_PROGRAM,
DIRTY_OBJECT_TEXTURES_INIT, DIRTY_OBJECT_TEXTURES_INIT,
...@@ -578,7 +577,6 @@ class State : angle::NonCopyable ...@@ -578,7 +577,6 @@ class State : angle::NonCopyable
angle::Result syncDrawAttachments(const Context *context); angle::Result syncDrawAttachments(const Context *context);
angle::Result syncVertexArray(const Context *context); angle::Result syncVertexArray(const Context *context);
angle::Result syncTextures(const Context *context); angle::Result syncTextures(const Context *context);
angle::Result syncImages(const Context *context);
angle::Result syncSamplers(const Context *context); angle::Result syncSamplers(const Context *context);
angle::Result syncProgram(const Context *context); angle::Result syncProgram(const Context *context);
angle::Result syncTexturesInit(const Context *context); angle::Result syncTexturesInit(const Context *context);
...@@ -587,21 +585,19 @@ class State : angle::NonCopyable ...@@ -587,21 +585,19 @@ class State : angle::NonCopyable
using DirtyObjectHandler = angle::Result (State::*)(const Context *context); using DirtyObjectHandler = angle::Result (State::*)(const Context *context);
static constexpr DirtyObjectHandler kDirtyObjectHandlers[DIRTY_OBJECT_MAX] = { static constexpr DirtyObjectHandler kDirtyObjectHandlers[DIRTY_OBJECT_MAX] = {
&State::syncReadFramebuffer, &State::syncDrawFramebuffer, &State::syncDrawAttachments, &State::syncReadFramebuffer, &State::syncDrawFramebuffer, &State::syncDrawAttachments,
&State::syncVertexArray, &State::syncTextures, &State::syncImages, &State::syncVertexArray, &State::syncTextures, &State::syncSamplers,
&State::syncSamplers, &State::syncProgram, &State::syncTexturesInit, &State::syncProgram, &State::syncTexturesInit, &State::syncImagesInit};
&State::syncImagesInit};
static_assert(DIRTY_OBJECT_READ_FRAMEBUFFER == 0, "check DIRTY_OBJECT_READ_FRAMEBUFFER index"); static_assert(DIRTY_OBJECT_READ_FRAMEBUFFER == 0, "check DIRTY_OBJECT_READ_FRAMEBUFFER index");
static_assert(DIRTY_OBJECT_DRAW_FRAMEBUFFER == 1, "check DIRTY_OBJECT_DRAW_FRAMEBUFFER index"); static_assert(DIRTY_OBJECT_DRAW_FRAMEBUFFER == 1, "check DIRTY_OBJECT_DRAW_FRAMEBUFFER index");
static_assert(DIRTY_OBJECT_DRAW_ATTACHMENTS == 2, "check DIRTY_OBJECT_DRAW_ATTACHMENTS index"); static_assert(DIRTY_OBJECT_DRAW_ATTACHMENTS == 2, "check DIRTY_OBJECT_DRAW_ATTACHMENTS index");
static_assert(DIRTY_OBJECT_VERTEX_ARRAY == 3, "check DIRTY_OBJECT_VERTEX_ARRAY index"); static_assert(DIRTY_OBJECT_VERTEX_ARRAY == 3, "check DIRTY_OBJECT_VERTEX_ARRAY index");
static_assert(DIRTY_OBJECT_TEXTURES == 4, "check DIRTY_OBJECT_TEXTURES index"); static_assert(DIRTY_OBJECT_TEXTURES == 4, "check DIRTY_OBJECT_TEXTURES index");
static_assert(DIRTY_OBJECT_IMAGES == 5, "check DIRTY_OBJECT_IMAGES index"); static_assert(DIRTY_OBJECT_SAMPLERS == 5, "check DIRTY_OBJECT_SAMPLERS index");
static_assert(DIRTY_OBJECT_SAMPLERS == 6, "check DIRTY_OBJECT_SAMPLERS index"); static_assert(DIRTY_OBJECT_PROGRAM == 6, "check DIRTY_OBJECT_PROGRAM index");
static_assert(DIRTY_OBJECT_PROGRAM == 7, "check DIRTY_OBJECT_PROGRAM index"); static_assert(DIRTY_OBJECT_TEXTURES_INIT == 7, "check DIRTY_OBJECT_TEXTURES_INIT index");
static_assert(DIRTY_OBJECT_TEXTURES_INIT == 8, "check DIRTY_OBJECT_TEXTURES_INIT index"); static_assert(DIRTY_OBJECT_IMAGES_INIT == 8, "check DIRTY_OBJECT_IMAGES_INIT index");
static_assert(DIRTY_OBJECT_IMAGES_INIT == 9, "check DIRTY_OBJECT_IMAGES_INIT index"); static_assert(DIRTY_OBJECT_MAX == 9, "check DIRTY_OBJECT_MAX");
static_assert(DIRTY_OBJECT_MAX == 10, "check DIRTY_OBJECT_MAX");
// Dispatch table for buffer update functions. // Dispatch table for buffer update functions.
static const angle::PackedEnumMap<BufferBinding, BufferBindingSetter> kBufferSetters; static const angle::PackedEnumMap<BufferBinding, BufferBindingSetter> kBufferSetters;
......
...@@ -1043,6 +1043,18 @@ TEST_P(RobustResourceInitTestES31, ImageTextureInit_R32UI) ...@@ -1043,6 +1043,18 @@ TEST_P(RobustResourceInitTestES31, ImageTextureInit_R32UI)
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
EXPECT_EQ(200u, outputValue); EXPECT_EQ(200u, outputValue);
outputValue = 0u;
// Write to another uninitialized texture.
GLTexture texture2;
glBindTexture(GL_TEXTURE_2D, texture2);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
EXPECT_GL_NO_ERROR();
glBindImageTexture(1, texture2, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
glDispatchCompute(1, 1, 1);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture2, 0);
glReadPixels(0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &outputValue);
EXPECT_EQ(200u, outputValue);
} }
// Basic test that renderbuffers are initialized correctly. // Basic test that renderbuffers are initialized correctly.
......
...@@ -1200,6 +1200,64 @@ class SimpleStateChangeTest : public ANGLETest ...@@ -1200,6 +1200,64 @@ class SimpleStateChangeTest : public ANGLETest
class SimpleStateChangeTestES3 : public SimpleStateChangeTest class SimpleStateChangeTestES3 : public SimpleStateChangeTest
{}; {};
class SimpleStateChangeTestES31 : public SimpleStateChangeTest
{
protected:
void SetUp() override
{
ANGLETest::SetUp();
glGenFramebuffers(1, &mFramebuffer);
glGenTextures(1, &mTexture);
glBindTexture(GL_TEXTURE_2D, mTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 2, 2);
EXPECT_GL_NO_ERROR();
constexpr char kCS[] = R"(#version 310 es
layout(local_size_x=2, local_size_y=2) in;
layout (rgba8, binding = 0) readonly uniform highp image2D srcImage;
layout (rgba8, binding = 1) writeonly uniform highp image2D dstImage;
void main()
{
imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)));
})";
mProgram = CompileComputeProgram(kCS);
ASSERT_NE(mProgram, 0u);
glBindImageTexture(1, mTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture,
0);
ASSERT_GL_NO_ERROR();
}
void TearDown() override
{
if (mFramebuffer != 0)
{
glDeleteFramebuffers(1, &mFramebuffer);
mFramebuffer = 0;
}
if (mTexture != 0)
{
glDeleteTextures(1, &mTexture);
mTexture = 0;
}
glDeleteProgram(mProgram);
ANGLETest::TearDown();
}
GLuint mProgram;
GLuint mFramebuffer = 0;
GLuint mTexture = 0;
};
constexpr char kSimpleVertexShader[] = R"(attribute vec2 position; constexpr char kSimpleVertexShader[] = R"(attribute vec2 position;
attribute vec4 color; attribute vec4 color;
varying vec4 vColor; varying vec4 vColor;
...@@ -2223,6 +2281,163 @@ void main() ...@@ -2223,6 +2281,163 @@ void main()
EXPECT_PIXEL_RECT_EQ(kHalfSize, kHalfSize, kHalfSize, kHalfSize, GLColor::yellow); EXPECT_PIXEL_RECT_EQ(kHalfSize, kHalfSize, kHalfSize, kHalfSize, GLColor::yellow);
} }
// Tests that deleting an in-flight image texture does not immediately delete the resource.
TEST_P(SimpleStateChangeTestES31, DeleteImageTextureInUse)
{
std::array<GLColor, 4> colors = {
{GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow}};
GLTexture texRead;
glBindTexture(GL_TEXTURE_2D, texRead);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 2, 2);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
EXPECT_GL_NO_ERROR();
glUseProgram(mProgram);
glBindImageTexture(0, texRead, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
glDispatchCompute(1, 1, 1);
texRead.reset();
std::array<GLColor, 4> results;
glReadPixels(0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, results.data());
EXPECT_GL_NO_ERROR();
for (int i = 0; i < 4; i++)
{
EXPECT_EQ(colors[i], results[i]);
}
}
// Tests that bind the same image texture all the time between different dispatch calls.
TEST_P(SimpleStateChangeTestES31, RebindImageTextureDispatchAgain)
{
std::array<GLColor, 4> colors = {{GLColor::cyan, GLColor::cyan, GLColor::cyan, GLColor::cyan}};
GLTexture texRead;
glBindTexture(GL_TEXTURE_2D, texRead);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 2, 2);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
glUseProgram(mProgram);
glBindImageTexture(0, texRead, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
glDispatchCompute(1, 1, 1);
// Bind again
glBindImageTexture(0, texRead, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
glDispatchCompute(1, 1, 1);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_RECT_EQ(0, 0, 2, 2, GLColor::cyan);
}
// Tests that we can dispatch with an image texture, modify the image texture with a texSubImage,
// and then dispatch again correctly.
TEST_P(SimpleStateChangeTestES31, DispatchWithImageTextureTexSubImageThenDispatchAgain)
{
std::array<GLColor, 4> colors = {{GLColor::red, GLColor::red, GLColor::red, GLColor::red}};
std::array<GLColor, 4> subColors = {
{GLColor::green, GLColor::green, GLColor::green, GLColor::green}};
GLTexture texRead;
glBindTexture(GL_TEXTURE_2D, texRead);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 2, 2);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, colors.data());
glUseProgram(mProgram);
glBindImageTexture(0, texRead, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
glDispatchCompute(1, 1, 1);
// Update bottom-half of image texture with green.
glBindTexture(GL_TEXTURE_2D, texRead);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 1, GL_RGBA, GL_UNSIGNED_BYTE, subColors.data());
ASSERT_GL_NO_ERROR();
// Dispatch again, should still work.
glDispatchCompute(1, 1, 1);
ASSERT_GL_NO_ERROR();
// Validate first half of the image is red and the bottom is green.
std::array<GLColor, 4> results;
glReadPixels(0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, results.data());
EXPECT_GL_NO_ERROR();
EXPECT_EQ(GLColor::green, results[0]);
EXPECT_EQ(GLColor::green, results[1]);
EXPECT_EQ(GLColor::red, results[2]);
EXPECT_EQ(GLColor::red, results[3]);
}
// Test updating an image texture's contents while in use by GL works as expected.
TEST_P(SimpleStateChangeTestES31, UpdateImageTextureInUse)
{
std::array<GLColor, 4> rgby = {{GLColor::red, GLColor::green, GLColor::blue, GLColor::yellow}};
GLTexture texRead;
glBindTexture(GL_TEXTURE_2D, texRead);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 2, 2);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, rgby.data());
glUseProgram(mProgram);
glBindImageTexture(0, texRead, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
glDispatchCompute(1, 1, 1);
// Update the texture to be YBGR, while the Texture is in-use. Should not affect the dispatch.
glBindTexture(GL_TEXTURE_2D, texRead);
std::array<GLColor, 4> ybgr = {{GLColor::yellow, GLColor::blue, GLColor::green, GLColor::red}};
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, ybgr.data());
ASSERT_GL_NO_ERROR();
// Check the Framebuffer. The dispatch call should have completed with the original RGBY data.
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(0, 1, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::yellow);
// Dispatch again. The second dispatch call should use the updated YBGR data.
glDispatchCompute(1, 1, 1);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
EXPECT_PIXEL_COLOR_EQ(1, 0, GLColor::blue);
EXPECT_PIXEL_COLOR_EQ(0, 1, GLColor::green);
EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
ASSERT_GL_NO_ERROR();
}
// Test that we can alternate between image textures between different dispatchs.
TEST_P(SimpleStateChangeTestES31, DispatchImageTextureAThenTextureBThenTextureA)
{
std::array<GLColor, 4> colorsTexA = {
{GLColor::cyan, GLColor::cyan, GLColor::cyan, GLColor::cyan}};
std::array<GLColor, 4> colorsTexB = {
{GLColor::magenta, GLColor::magenta, GLColor::magenta, GLColor::magenta}};
GLTexture texA;
glBindTexture(GL_TEXTURE_2D, texA);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 2, 2);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, colorsTexA.data());
GLTexture texB;
glBindTexture(GL_TEXTURE_2D, texB);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 2, 2);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, colorsTexB.data());
glUseProgram(mProgram);
glBindImageTexture(0, texA, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
glDispatchCompute(1, 1, 1);
glBindImageTexture(0, texB, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
glDispatchCompute(1, 1, 1);
glBindImageTexture(0, texA, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
glDispatchCompute(1, 1, 1);
EXPECT_PIXEL_RECT_EQ(0, 0, 2, 2, GLColor::cyan);
ASSERT_GL_NO_ERROR();
}
static constexpr char kColorVS[] = R"(attribute vec2 position; static constexpr char kColorVS[] = R"(attribute vec2 position;
attribute vec4 color; attribute vec4 color;
varying vec4 vColor; varying vec4 vColor;
...@@ -3096,6 +3311,7 @@ ANGLE_INSTANTIATE_TEST(StateChangeRenderTest, ...@@ -3096,6 +3311,7 @@ ANGLE_INSTANTIATE_TEST(StateChangeRenderTest,
ANGLE_INSTANTIATE_TEST(StateChangeTestES3, ES3_D3D11(), ES3_OPENGL()); ANGLE_INSTANTIATE_TEST(StateChangeTestES3, ES3_D3D11(), ES3_OPENGL());
ANGLE_INSTANTIATE_TEST(SimpleStateChangeTest, ES2_VULKAN(), ES2_OPENGL()); ANGLE_INSTANTIATE_TEST(SimpleStateChangeTest, ES2_VULKAN(), ES2_OPENGL());
ANGLE_INSTANTIATE_TEST(SimpleStateChangeTestES3, ES3_OPENGL(), ES3_D3D11()); ANGLE_INSTANTIATE_TEST(SimpleStateChangeTestES3, ES3_OPENGL(), ES3_D3D11());
ANGLE_INSTANTIATE_TEST(SimpleStateChangeTestES31, ES31_OPENGL(), ES31_D3D11());
ANGLE_INSTANTIATE_TEST(ValidationStateChangeTest, ES3_D3D11(), ES3_OPENGL()); ANGLE_INSTANTIATE_TEST(ValidationStateChangeTest, ES3_D3D11(), ES3_OPENGL());
ANGLE_INSTANTIATE_TEST(WebGL2ValidationStateChangeTest, ES3_D3D11(), ES3_OPENGL()); ANGLE_INSTANTIATE_TEST(WebGL2ValidationStateChangeTest, ES3_D3D11(), ES3_OPENGL());
ANGLE_INSTANTIATE_TEST(ValidationStateChangeTestES31, ES31_OPENGL()); ANGLE_INSTANTIATE_TEST(ValidationStateChangeTestES31, ES31_OPENGL(), ES31_D3D11());
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