aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeoff Lang <geofflang@google.com>2022-01-28 13:46:41 -0500
committerAngle LUCI CQ <angle-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-04-19 18:34:52 +0000
commite18240d136d15e5cdfa4fa4a6355ca21c8d807b6 (patch)
treed98a6e0868b16fc062f802462789701ec09a19a6
parentbddb944bc0beb94af5934751159e26aeadb8fdf5 (diff)
downloadangle-e18240d136d15e5cdfa4fa4a6355ca21c8d807b6.tar.gz
Mark contexts as shared when importing EGL images.
Once a context references an EGL image, it can share resources with contexts in other share groups. Marking the context as shared ensures that locks are held by all contexts referencing EGL images for GL functions. Bug: angleproject:6957 Change-Id: Ic3901c458f388306c59f6bb01560a7c66d0574c0 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3424659 Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: mohan maiya <m.maiya@samsung.com> Commit-Queue: Geoff Lang <geofflang@chromium.org>
-rw-r--r--src/libANGLE/Context.cpp8
-rw-r--r--src/libANGLE/Display.cpp9
-rw-r--r--src/libANGLE/Display.h2
-rw-r--r--src/libANGLE/Image.cpp1
-rw-r--r--src/tests/gl_tests/MultithreadingTest.cpp80
5 files changed, 98 insertions, 2 deletions
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 213b4c3bd0..9356bf22a5 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -8949,6 +8949,8 @@ void Context::importSemaphoreZirconHandle(SemaphoreID semaphore,
void Context::eGLImageTargetTexStorage(GLenum target, GLeglImageOES image, const GLint *attrib_list)
{
+ setShared();
+
Texture *texture = getTextureByType(FromGLenum<TextureType>(target));
egl::Image *imageObject = static_cast<egl::Image *>(image);
ANGLE_CONTEXT_TRY(texture->setStorageEGLImageTarget(this, FromGLenum<TextureType>(target),
@@ -8959,11 +8961,15 @@ void Context::eGLImageTargetTextureStorage(GLuint texture,
GLeglImageOES image,
const GLint *attrib_list)
{
+ setShared();
+
return;
}
void Context::eGLImageTargetTexture2D(TextureType target, GLeglImageOES image)
{
+ setShared();
+
Texture *texture = getTextureByType(target);
egl::Image *imageObject = static_cast<egl::Image *>(image);
ANGLE_CONTEXT_TRY(texture->setEGLImageTarget(this, target, imageObject));
@@ -8971,6 +8977,8 @@ void Context::eGLImageTargetTexture2D(TextureType target, GLeglImageOES image)
void Context::eGLImageTargetRenderbufferStorage(GLenum target, GLeglImageOES image)
{
+ setShared();
+
Renderbuffer *renderbuffer = mState.getCurrentRenderbuffer();
egl::Image *imageObject = static_cast<egl::Image *>(image);
ANGLE_CONTEXT_TRY(renderbuffer->setStorageEGLImageTarget(this, imageObject));
diff --git a/src/libANGLE/Display.cpp b/src/libANGLE/Display.cpp
index bd2bd59d77..d7b75bf625 100644
--- a/src/libANGLE/Display.cpp
+++ b/src/libANGLE/Display.cpp
@@ -1325,7 +1325,7 @@ Error Display::createPixmapSurface(const Config *configuration,
return NoError();
}
-Error Display::createImage(const gl::Context *context,
+Error Display::createImage(gl::Context *context,
EGLenum target,
EGLClientBuffer buffer,
const AttributeMap &attribs,
@@ -1357,6 +1357,13 @@ Error Display::createImage(const gl::Context *context,
}
ASSERT(sibling != nullptr);
+ if (context)
+ {
+ // If the source comes from a context, make sure it's marked as shared because its resources
+ // can now be used by contects outside of its share group.
+ context->setShared();
+ }
+
angle::UniqueObjectPointer<Image, Display> imagePtr(
new Image(mImplementation, context, target, sibling, attribs), this);
ANGLE_TRY(imagePtr->initialize(this));
diff --git a/src/libANGLE/Display.h b/src/libANGLE/Display.h
index 7e7abb695f..46aedc60b9 100644
--- a/src/libANGLE/Display.h
+++ b/src/libANGLE/Display.h
@@ -180,7 +180,7 @@ class Display final : public LabeledObject,
const AttributeMap &attribs,
Surface **outSurface);
- Error createImage(const gl::Context *context,
+ Error createImage(gl::Context *context,
EGLenum target,
EGLClientBuffer buffer,
const AttributeMap &attribs,
diff --git a/src/libANGLE/Image.cpp b/src/libANGLE/Image.cpp
index 995cb41e40..83e1a89618 100644
--- a/src/libANGLE/Image.cpp
+++ b/src/libANGLE/Image.cpp
@@ -291,6 +291,7 @@ Image::Image(rx::EGLImplFactory *factory,
{
ASSERT(mImplementation != nullptr);
ASSERT(buffer != nullptr);
+ ASSERT(context == nullptr || context->isShared());
mState.source->addImageSource(this);
}
diff --git a/src/tests/gl_tests/MultithreadingTest.cpp b/src/tests/gl_tests/MultithreadingTest.cpp
index 806f1ea2b7..909f66bfb7 100644
--- a/src/tests/gl_tests/MultithreadingTest.cpp
+++ b/src/tests/gl_tests/MultithreadingTest.cpp
@@ -352,6 +352,86 @@ TEST_P(MultithreadingTest, MultiContextDraw)
runMultithreadedGLTest(testBody, 4);
}
+// Test that multiple threads can draw and readback pixels successfully at the same time while EGL
+// images are bound between them
+TEST_P(MultithreadingTest, MultiContextDrawWithEGLImage)
+{
+ ANGLE_SKIP_TEST_IF(!platformSupportsMultithreading());
+
+ ANGLE_SKIP_TEST_IF(isSwiftshader());
+
+ EGLWindow *window = getEGLWindow();
+ EGLDisplay dpy = window->getDisplay();
+ ANGLE_SKIP_TEST_IF(IsGLExtensionEnabled("GL_OES_EGL_image"));
+ ANGLE_SKIP_TEST_IF(IsEGLDisplayExtensionEnabled(dpy, "EGL_KHR_gl_texture_2D_image"));
+
+ // Create a source 2D texture
+ GLTexture sourceTexture;
+ glBindTexture(GL_TEXTURE_2D, sourceTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::red);
+
+ // Disable mipmapping
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ ASSERT_GL_NO_ERROR();
+
+ // Create an image from the source texture
+ constexpr EGLint attribs[] = {
+ EGL_IMAGE_PRESERVED,
+ EGL_TRUE,
+ EGL_NONE,
+ };
+ EGLImageKHR image = eglCreateImageKHR(
+ dpy, window->getContext(), EGL_GL_TEXTURE_2D_KHR,
+ reinterpret_cast<EGLClientBuffer>(static_cast<size_t>(sourceTexture.get())), attribs);
+
+ auto testBody = [image](EGLSurface surface, size_t thread) {
+ constexpr size_t kIterationsPerThread = 32;
+ constexpr size_t kDrawsPerIteration = 500;
+
+ // Just bind the EGL image to this context and leave it bound while drawing
+ GLTexture destTexture;
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, destTexture);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image);
+
+ ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
+ glUseProgram(program);
+
+ GLint colorLocation = glGetUniformLocation(program, essl1_shaders::ColorUniform());
+
+ auto quadVertices = GetQuadVertices();
+
+ GLBuffer vertexBuffer;
+ glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * 6, quadVertices.data(), GL_STATIC_DRAW);
+
+ GLint positionLocation = glGetAttribLocation(program, essl1_shaders::PositionAttrib());
+ glEnableVertexAttribArray(positionLocation);
+ glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
+
+ for (size_t iteration = 0; iteration < kIterationsPerThread; iteration++)
+ {
+ // Base the clear color on the thread and iteration indexes so every clear color is
+ // unique
+ const GLColor color(static_cast<GLubyte>(thread % 255),
+ static_cast<GLubyte>(iteration % 255), 0, 255);
+ const angle::Vector4 floatColor = color.toNormalizedVector();
+ glUniform4fv(colorLocation, 1, floatColor.data());
+
+ for (size_t draw = 0; draw < kDrawsPerIteration; draw++)
+ {
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ }
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, color);
+ }
+ };
+ runMultithreadedGLTest(testBody, 4);
+
+ eglDestroyImage(dpy, image);
+}
+
// Test that multiple threads can draw and read back pixels correctly.
// Using eglSwapBuffers stresses race conditions around use of QueueSerials.
TEST_P(MultithreadingTest, MultiContextDrawWithSwapBuffers)