External Texture Support In MEC
Bug: angleproject:4964
Change-Id: I5cfbadf515a30fb20d75b2d745fdecdafa12268f
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3812378
Reviewed-by: Yuxin Hu <yuxinhu@google.com>
Auto-Submit: Faye Zhang <ffz@google.com>
Commit-Queue: Faye Zhang <ffz@google.com>
Reviewed-by: Cody Northrop <cnorthrop@google.com>
diff --git a/src/libANGLE/capture/FrameCapture.cpp b/src/libANGLE/capture/FrameCapture.cpp
index 12dd107..1bd9526 100644
--- a/src/libANGLE/capture/FrameCapture.cpp
+++ b/src/libANGLE/capture/FrameCapture.cpp
@@ -32,6 +32,7 @@
#include "libANGLE/Shader.h"
#include "libANGLE/Surface.h"
#include "libANGLE/VertexArray.h"
+#include "libANGLE/capture/capture_egl.h"
#include "libANGLE/capture/capture_gles_1_0_autogen.h"
#include "libANGLE/capture/capture_gles_2_0_autogen.h"
#include "libANGLE/capture/capture_gles_3_0_autogen.h"
@@ -43,6 +44,7 @@
#include "libANGLE/entry_points_utils.h"
#include "libANGLE/queryconversions.h"
#include "libANGLE/queryutils.h"
+#include "libANGLE/validationEGL.h"
#include "third_party/ceval/ceval.h"
#define USE_SYSTEM_ZLIB
@@ -2887,6 +2889,18 @@
return;
}
+ if (index.getType() == gl::TextureType::External)
+ {
+ // The generated glTexImage2D call is for creating the staging texture
+ Capture(setupCalls,
+ CaptureTexImage2D(*replayState, true, gl::TextureTarget::_2D, index.getLevelIndex(),
+ format.internalFormat, desc.size.width, desc.size.height, 0,
+ format.format, format.type, data));
+
+ // For external textures, we're done
+ return;
+ }
+
bool is3D =
(index.getType() == gl::TextureType::_3D || index.getType() == gl::TextureType::_2DArray ||
index.getType() == gl::TextureType::CubeMapArray);
@@ -3267,12 +3281,13 @@
// Capture the setup of the state that's shared by all of the contexts in the share group
// See IsSharedObjectResource for the list of objects covered here.
-void CaptureShareGroupMidExecutionSetup(const gl::Context *context,
- std::vector<CallCapture> *setupCalls,
- ResourceTracker *resourceTracker,
- gl::State &replayState)
+void CaptureShareGroupMidExecutionSetup(
+ const gl::Context *context,
+ std::vector<CallCapture> *setupCalls,
+ ResourceTracker *resourceTracker,
+ gl::State &replayState,
+ const PackedEnumMap<ResourceIDType, uint32_t> &maxAccessedResourceIDs)
{
-
FrameCaptureShared *frameCaptureShared = context->getShareGroup()->getFrameCaptureShared();
const gl::State &apiState = context->getState();
@@ -3574,7 +3589,8 @@
index.getType() == gl::TextureType::_2DArray ||
index.getType() == gl::TextureType::Buffer ||
index.getType() == gl::TextureType::CubeMap ||
- index.getType() == gl::TextureType::CubeMapArray);
+ index.getType() == gl::TextureType::CubeMapArray ||
+ index.getType() == gl::TextureType::External);
// Check for supported textures
if (!supportedType)
@@ -3594,6 +3610,20 @@
continue;
}
+ // create a staging GL_TEXTURE_2D texture to create the eglImage with
+ gl::TextureID stagingTexId = {maxAccessedResourceIDs[ResourceIDType::Texture] + 1};
+ if (index.getType() == gl::TextureType::External)
+ {
+ Capture(setupCalls, CaptureGenTextures(replayState, true, 1, &stagingTexId));
+ MaybeCaptureUpdateResourceIDs(context, resourceTracker, setupCalls);
+ Capture(setupCalls,
+ CaptureBindTexture(replayState, true, gl::TextureType::_2D, stagingTexId));
+ Capture(setupCalls, CaptureTexParameteri(replayState, true, gl::TextureType::_2D,
+ GL_TEXTURE_MIN_FILTER, GL_NEAREST));
+ Capture(setupCalls, CaptureTexParameteri(replayState, true, gl::TextureType::_2D,
+ GL_TEXTURE_MAG_FILTER, GL_NEAREST));
+ }
+
if (context->getExtensions().getImageANGLE)
{
// Use ANGLE_get_image to read back pixel data.
@@ -3643,6 +3673,37 @@
CaptureTextureContents(calls, &replayState, texture, index, desc,
static_cast<GLuint>(data.size()), data.data());
}
+
+ if (index.getType() == gl::TextureType::External)
+ {
+ constexpr EGLint attribs[] = {
+ EGL_IMAGE_PRESERVED,
+ EGL_TRUE,
+ EGL_NONE,
+ };
+ const egl::AttributeMap &attrib_listPacked =
+ egl::PackParam<const egl::AttributeMap &>(attribs);
+ attrib_listPacked.initializeWithoutValidation();
+
+ // Create the image on demand
+ egl::Image *image = nullptr;
+ Capture(setupCalls,
+ CaptureEGLCreateImage(context, EGL_GL_TEXTURE_2D_KHR,
+ reinterpret_cast<EGLClientBuffer>(
+ static_cast<GLuint64>(stagingTexId.value)),
+ attrib_listPacked, image));
+
+ // Pass the eglImage to the texture that is bound to GL_TEXTURE_EXTERNAL_OES
+ // target
+ for (std::vector<CallCapture> *calls : texSetupCalls)
+ {
+ Capture(calls, CaptureEGLImageTargetTexture2DOES(
+ replayState, true, gl::TextureType::External, image));
+ }
+
+ // Delete the staging texture
+ Capture(setupCalls, CaptureDeleteTextures(replayState, true, 1, &stagingTexId));
+ }
}
else
{
@@ -6399,11 +6460,13 @@
break;
}
+
case EntryPoint::GLCopyBufferSubData:
{
maybeCaptureCoherentBuffers(context);
break;
}
+
case EntryPoint::GLDeleteFramebuffers:
case EntryPoint::GLDeleteFramebuffersOES:
{
@@ -6423,6 +6486,7 @@
}
break;
}
+
case EntryPoint::GLUseProgram:
{
if (isCaptureActive())
@@ -6432,6 +6496,7 @@
}
break;
}
+
case EntryPoint::GLGenVertexArrays:
case EntryPoint::GLGenVertexArraysOES:
{
@@ -6445,6 +6510,7 @@
}
break;
}
+
case EntryPoint::GLDeleteVertexArrays:
case EntryPoint::GLDeleteVertexArraysOES:
{
@@ -6459,6 +6525,7 @@
}
break;
}
+
case EntryPoint::GLBindVertexArray:
case EntryPoint::GLBindVertexArrayOES:
{
@@ -6469,6 +6536,38 @@
}
break;
}
+
+ case EntryPoint::EGLCreateImage:
+ case EntryPoint::EGLCreateImageKHR:
+ {
+ ParamData attribs =
+ call.params.getParam("attrib_list", ParamType::TGLint64Pointer, 4).data;
+
+ int bytesPerAttrib = 8;
+ int numAttribs = static_cast<int>(attribs[0].size() / bytesPerAttrib);
+ std::vector<GLint64> reconstructedAttribs(numAttribs);
+ for (int i = 0; i < numAttribs; i++)
+ {
+ GLint64 compiledAttrib = 0;
+ for (int b = 0; b < bytesPerAttrib; b++)
+ {
+ compiledAttrib |= attribs[0][i * bytesPerAttrib + b] << (b * sizeof(uint64_t));
+ }
+ reconstructedAttribs[i] = compiledAttrib;
+ }
+
+ // Check if the passed-in attribs are as expected, otherwise throw an UNREACHABLE
+ if (!isCaptureActive() &&
+ (reconstructedAttribs[0] != EGL_IMAGE_PRESERVED ||
+ reconstructedAttribs[1] != EGL_TRUE || reconstructedAttribs[2] != EGL_NONE))
+ {
+ ERR() << "EGLImage created with " << numAttribs << " unsupported attribs types.";
+ UNREACHABLE();
+ }
+
+ break;
+ }
+
default:
break;
}
@@ -6976,7 +7075,7 @@
mainContextReplayState.initializeForCapture(mainContext);
CaptureShareGroupMidExecutionSetup(mainContext, &mShareGroupSetupCalls, &mResourceTracker,
- mainContextReplayState);
+ mainContextReplayState, mMaxAccessedResourceIDs);
scanSetupCalls(mainContext, mShareGroupSetupCalls);
diff --git a/src/libANGLE/capture/capture_egl.cpp b/src/libANGLE/capture/capture_egl.cpp
index 6ad2a43..5f8945f 100644
--- a/src/libANGLE/capture/capture_egl.cpp
+++ b/src/libANGLE/capture/capture_egl.cpp
@@ -128,7 +128,7 @@
std::move(paramBuffer));
}
-angle::CallCapture CaptureEGLCreateImage(gl::Context *context,
+angle::CallCapture CaptureEGLCreateImage(const gl::Context *context,
EGLenum target,
EGLClientBuffer buffer,
const egl::AttributeMap &attributes,
diff --git a/src/libANGLE/capture/capture_egl.h b/src/libANGLE/capture/capture_egl.h
index e8e2fc6..f23bc1a 100644
--- a/src/libANGLE/capture/capture_egl.h
+++ b/src/libANGLE/capture/capture_egl.h
@@ -45,7 +45,7 @@
angle::CallCapture CaptureCreateNativeClientBufferANDROID(const egl::AttributeMap &attribMap,
EGLClientBuffer eglClientBuffer);
-angle::CallCapture CaptureEGLCreateImage(gl::Context *context,
+angle::CallCapture CaptureEGLCreateImage(const gl::Context *context,
EGLenum target,
EGLClientBuffer buffer,
const egl::AttributeMap &attributes,
diff --git a/src/tests/capture_replay_tests/capture_replay_expectations.txt b/src/tests/capture_replay_tests/capture_replay_expectations.txt
index 4ef3a5a..03459df 100644
--- a/src/tests/capture_replay_tests/capture_replay_expectations.txt
+++ b/src/tests/capture_replay_tests/capture_replay_expectations.txt
@@ -162,3 +162,19 @@
7483 : MultisampleTestES3.ResolveToFBO/* = SKIP_FOR_CAPTURE
6723 : EGLMultiContextTest.ReuseUnterminatedDisplay/* = SKIP_FOR_CAPTURE
+
+# No support yet for Capture/Replay of External Textures using other attribs
+7570 : ImageTest.MipLevels/* = SKIP_FOR_CAPTURE
+7570 : ImageTest.Source2DTarget2D_Colorspace/* = SKIP_FOR_CAPTURE
+7570 : ImageTest.Source2DTarget2DArray_Colorspace/* = SKIP_FOR_CAPTURE
+7570 : ImageTest.Source2DTargetExternal_Colorspace/* = SKIP_FOR_CAPTURE
+7570 : ImageTest.SourceCubeTarget2D_Colorspace/* = SKIP_FOR_CAPTURE
+7570 : ImageTest.SourceCubeTargetExternal_Colorspace/* = SKIP_FOR_CAPTURE
+7570 : ImageTest.SourceRenderbufferTargetTexture_Colorspace/* = SKIP_FOR_CAPTURE
+7570 : ImageTest.SourceRenderbufferTargetTextureExternal_Colorspace/* = SKIP_FOR_CAPTURE
+7570 : ImageTest.ValidationGLEGLImage_Colorspace/* = SKIP_FOR_CAPTURE
+7570 : ImageTest.ValidationImageBase/* = SKIP_FOR_CAPTURE
+7570 : ImageTestES3.Source2DTargetExternalESSL3_Colorspace/* = SKIP_FOR_CAPTURE
+7570 : ImageTestES3.SourceCubeTargetExternalESSL3/* = SKIP_FOR_CAPTURE
+7570 : ImageTestES3.SourceCubeTargetExternalESSL3_Colorspace/* = SKIP_FOR_CAPTURE
+7570 : ImageTestES3.SourceRenderbufferTargetTextureExternalESSL3_Colorspace/* = SKIP_FOR_CAPTURE
\ No newline at end of file
diff --git a/src/tests/gl_tests/ImageTest.cpp b/src/tests/gl_tests/ImageTest.cpp
index 57dcda1..053617c 100644
--- a/src/tests/gl_tests/ImageTest.cpp
+++ b/src/tests/gl_tests/ImageTest.cpp
@@ -5526,6 +5526,199 @@
}
}
+// Case for testing External Texture support in MEC.
+// To run this test with the right capture setting, make sure to set these environment variables:
+//
+// For Linux:
+// export ANGLE_CAPTURE_FRAME_START=2
+// export ANGLE_CAPTURE_FRAME_END=2
+// export ANGLE_CAPTURE_LABEL=external_textures
+// export ANGLE_CAPTURE_OUT_DIR=[PATH_TO_ANGLE]/src/tests/restricted_traces/external_textures/
+//
+// For Android:
+// adb shell setprop debug.angle.capture.frame_start 2
+// adb shell setprop debug.angle.capture.frame_end 2
+// adb shell setprop debug.angle.capture.label external_textures
+// adb shell setprop debug.angle.capture.out_dir /data/data/externaltextures/angle_capture/
+TEST_P(ImageTest, AppTraceExternalTextureUseCase)
+{
+ EGLWindow *window = getEGLWindow();
+ ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt() || !has2DTextureExt() ||
+ !hasExternalESSL3Ext());
+
+ constexpr EGLint attribs[] = {
+ EGL_IMAGE_PRESERVED,
+ EGL_TRUE,
+ EGL_NONE,
+ };
+
+ // Create the Image
+ GLTexture sourceTexture1;
+ EGLImageKHR image1;
+
+ GLubyte data[] = {132, 55, 219, 255};
+ // Create a source 2D texture
+ glBindTexture(GL_TEXTURE_2D, sourceTexture1);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast<GLsizei>(1), static_cast<GLsizei>(1), 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, data);
+
+ // 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();
+
+ image1 = eglCreateImageKHR(window->getDisplay(), window->getContext(), EGL_GL_TEXTURE_2D_KHR,
+ reinterpretHelper<EGLClientBuffer>(sourceTexture1.get()), attribs);
+
+ ASSERT_EGL_SUCCESS();
+
+ // Create the target
+ GLTexture targetTexture1;
+ // Create a target texture from the image
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, targetTexture1);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image1);
+
+ // Disable mipmapping
+ glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ ASSERT_GL_NO_ERROR();
+
+ // Calls On EndFrame(), with MidExecutionSetup to restore external texture targetTexture1 above
+ EGLDisplay display = getEGLWindow()->getDisplay();
+ EGLSurface surface = getEGLWindow()->getSurface();
+ eglSwapBuffers(display, surface);
+
+ // Create another eglImage with another associated texture
+ // Draw using the eglImage texture targetTexture1 created in frame 1
+ GLTexture sourceTexture2;
+ EGLImageKHR image2;
+
+ // Create a source 2D texture
+ glBindTexture(GL_TEXTURE_2D, sourceTexture2);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, static_cast<GLsizei>(1), static_cast<GLsizei>(1), 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, data);
+
+ // 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();
+
+ image2 = eglCreateImageKHR(window->getDisplay(), window->getContext(), EGL_GL_TEXTURE_2D_KHR,
+ reinterpretHelper<EGLClientBuffer>(sourceTexture2.get()), attribs);
+
+ ASSERT_EGL_SUCCESS();
+
+ // Create the target
+ GLTexture targetTexture2;
+ // Create a target texture from the image
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, targetTexture2);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image2);
+
+ // Disable mipmapping
+ glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ ASSERT_GL_NO_ERROR();
+ glUseProgram(mTextureExternalProgram);
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, targetTexture1);
+ glUniform1i(mTextureExternalUniformLocation, 0);
+
+ drawQuad(mTextureExternalProgram, "position", 0.5f);
+
+ // Calls On EndFrame() to save the gl calls creating external texture targetTexture2;
+ // We use this as a reference to check the gl calls we restore for targetTexture1
+ // in MidExecutionSetup
+ eglSwapBuffers(display, surface);
+
+ // Draw a quad with the targetTexture2
+ glUseProgram(mTextureExternalProgram);
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, targetTexture2);
+ glUniform1i(mTextureExternalUniformLocation, 0);
+
+ drawQuad(mTextureExternalProgram, "position", 0.5f);
+
+ eglSwapBuffers(display, surface);
+
+ // Clean up
+ eglDestroyImageKHR(window->getDisplay(), image1);
+ eglDestroyImageKHR(window->getDisplay(), image2);
+}
+
+// Alternate case for testing External Texture (created with AHB) support in MEC.
+// Make sure to use the following environment variables for the right capture setting on Android:
+//
+// adb shell setprop debug.angle.capture.frame_start 2
+// adb shell setprop debug.angle.capture.frame_end 2
+// adb shell setprop debug.angle.capture.label AHB_textures
+// adb shell setprop debug.angle.capture.out_dir /data/data/AHBtextures/angle_capture/
+TEST_P(ImageTest, AppTraceExternalTextureWithAHBUseCase)
+{
+ EGLWindow *window = getEGLWindow();
+
+ ANGLE_SKIP_TEST_IF(!IsAndroid());
+ ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt() || !has2DTextureExt());
+ ANGLE_SKIP_TEST_IF(!hasAndroidImageNativeBufferExt() || !hasAndroidHardwareBufferSupport());
+
+ GLubyte data[4] = {7, 51, 197, 231};
+
+ // Create the Image
+ AHardwareBuffer *source;
+ EGLImageKHR image;
+ createEGLImageAndroidHardwareBufferSource(1, 1, 1, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ kDefaultAHBUsage, kDefaultAttribs, {{data, 4}},
+ &source, &image);
+
+ // Create a texture target to bind the egl image & disable mipmapping
+ GLTexture target;
+ createEGLImageTargetTextureExternal(image, target);
+
+ // Calls On EndFrame(), with MidExecutionSetup to restore external target texture above
+ EGLDisplay display = getEGLWindow()->getDisplay();
+ EGLSurface surface = getEGLWindow()->getSurface();
+ eglSwapBuffers(display, surface);
+
+ // Create another eglImage with another associated texture
+ // Draw using the eglImage target texture created in frame 1
+ AHardwareBuffer *source2;
+ EGLImageKHR image2;
+ createEGLImageAndroidHardwareBufferSource(1, 1, 1, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ kDefaultAHBUsage, kDefaultAttribs, {{data, 4}},
+ &source2, &image2);
+
+ // Create another texture target to bind the egl image & disable mipmapping
+ GLTexture target2;
+ createEGLImageTargetTextureExternal(image, target2);
+
+ glUseProgram(mTextureExternalProgram);
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, target);
+ glUniform1i(mTextureExternalUniformLocation, 0);
+
+ drawQuad(mTextureExternalProgram, "position", 0.5f);
+
+ // Calls On EndFrame() to save the gl calls creating external texture target2;
+ // We use this as a reference to check the gl calls we restore for GLTexture target
+ // in MidExecutionSetup
+ eglSwapBuffers(display, surface);
+
+ // Draw a quad with the GLTexture target2
+ glUseProgram(mTextureExternalProgram);
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, target2);
+ glUniform1i(mTextureExternalUniformLocation, 0);
+
+ drawQuad(mTextureExternalProgram, "position", 0.5f);
+
+ eglSwapBuffers(display, surface);
+
+ // Clean up
+ eglDestroyImageKHR(window->getDisplay(), image);
+ eglDestroyImageKHR(window->getDisplay(), image2);
+}
+
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(ImageTest);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ImageTestES3);