Add a simple smoke test for GL_EXT_external_buffer.
Updated the makefile to allow usage of <string>.
Change-Id: I1b3b4bbc10e97442b6ac8067021aa10d19d6d612
Test: ran android.vr.cts on a Pixel device
Bug: 62660866
diff --git a/tests/vr/jni/Android.mk b/tests/vr/jni/Android.mk
index 26b267c..769b9ef 100644
--- a/tests/vr/jni/Android.mk
+++ b/tests/vr/jni/Android.mk
@@ -30,4 +30,6 @@
LOCAL_SDK_VERSION := current
+LOCAL_NDK_STL_VARIANT := c++_static
+
include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/vr/jni/VrExtensionsJni.cpp b/tests/vr/jni/VrExtensionsJni.cpp
index 571d83f..7ae832d9 100644
--- a/tests/vr/jni/VrExtensionsJni.cpp
+++ b/tests/vr/jni/VrExtensionsJni.cpp
@@ -21,6 +21,11 @@
#include <jni.h>
#include <stdlib.h>
#include <android/hardware_buffer.h>
+#include <android/log.h>
+#include <string>
+
+#define LOG_TAG "VrExtensionsJni"
+#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__)
using PFNEGLGETNATIVECLIENTBUFFERANDROID =
EGLClientBuffer(EGLAPIENTRYP)(const AHardwareBuffer* buffer);
@@ -28,12 +33,34 @@
using PFNGLEGLIMAGETARGETTEXTURE2DOESPROC = void(GL_APIENTRYP)(GLenum target,
void* image);
+using PFNGLBUFFERSTORAGEEXTERNALEXTPROC =
+ void(GL_APIENTRYP)(GLenum target, GLintptr offset, GLsizeiptr size,
+ void* clientBuffer, GLbitfield flags);
+
+using PFNGLMAPBUFFERRANGEPROC = void*(GL_APIENTRYP)(GLenum target,
+ GLintptr offset,
+ GLsizeiptr length,
+ GLbitfield access);
+
+using PFNGLUNMAPBUFFERPROC = void*(GL_APIENTRYP)(GLenum target);
+
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
PFNEGLGETNATIVECLIENTBUFFERANDROID eglGetNativeClientBufferANDROID;
PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glFramebufferTextureMultiviewOVR;
PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC
glFramebufferTextureMultisampleMultiviewOVR;
+PFNGLBUFFERSTORAGEEXTERNALEXTPROC glBufferStorageExternalEXT;
+PFNGLMAPBUFFERRANGEPROC glMapBufferRange;
+PFNGLUNMAPBUFFERPROC glUnmapBuffer;
+
+#define NO_ERROR 0
+#define GL_UNIFORM_BUFFER 0x8A11
+
+// Declare flags that are added to MapBufferRange via EXT_buffer_storage.
+// https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_buffer_storage.txt
+#define GL_MAP_PERSISTENT_BIT_EXT 0x0040
+#define GL_MAP_COHERENT_BIT_EXT 0x0080
#define LOAD_PROC(NAME, TYPE) \
NAME = reinterpret_cast<TYPE>(eglGetProcAddress(# NAME))
@@ -52,8 +79,8 @@
ASSERT((a) == (b), "assert failed on (" #a ") at " __FILE__ ":%d", __LINE__)
#define ASSERT_NE(a, b) \
ASSERT((a) != (b), "assert failed on (" #a ") at " __FILE__ ":%d", __LINE__)
-#define ASSERT_LE(a, b) \
- ASSERT((a) <= (b), "assert failed on (" #a ") at " __FILE__ ":%d", __LINE__)
+#define ASSERT_GT(a, b) \
+ ASSERT((a) > (b), "assert failed on (" #a ") at " __FILE__ ":%d", __LINE__)
void fail(JNIEnv* env, const char* format, ...) {
va_list args;
@@ -70,7 +97,7 @@
static void testEglImageArray(JNIEnv* env, AHardwareBuffer_Desc desc,
int nsamples) {
- ASSERT_LE(1, desc.layers);
+ ASSERT_GT(desc.layers, 1);
AHardwareBuffer* hwbuffer = nullptr;
int error = AHardwareBuffer_allocate(&desc, &hwbuffer);
ASSERT_FALSE(error);
@@ -155,3 +182,85 @@
}
}
}
+
+static void testExternalBuffer(JNIEnv* env, uint64_t usage, bool write_hwbuffer,
+ const std::string& test_string) {
+ // Create a blob AHardwareBuffer suitable for holding the string.
+ AHardwareBuffer_Desc desc = {};
+ desc.width = test_string.size();
+ desc.height = 1;
+ desc.layers = 1;
+ desc.format = AHARDWAREBUFFER_FORMAT_BLOB;
+ desc.usage = usage;
+ AHardwareBuffer* hwbuffer = nullptr;
+ int error = AHardwareBuffer_allocate(&desc, &hwbuffer);
+ ASSERT_EQ(error, NO_ERROR);
+ // Create EGLClientBuffer from the AHardwareBuffer.
+ EGLClientBuffer native_buffer = eglGetNativeClientBufferANDROID(hwbuffer);
+ ASSERT_TRUE(native_buffer);
+ // Create uniform buffer from EGLClientBuffer.
+ const GLbitfield flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT |
+ GL_MAP_COHERENT_BIT_EXT | GL_MAP_PERSISTENT_BIT_EXT;
+ GLuint buf = 0;
+ glGenBuffers(1, &buf);
+ glBindBuffer(GL_UNIFORM_BUFFER, buf);
+ ASSERT_EQ(glGetError(), GL_NO_ERROR);
+ const GLsizeiptr bufsize = desc.width * desc.height;
+ glBufferStorageExternalEXT(GL_UNIFORM_BUFFER, 0,
+ bufsize, native_buffer, flags);
+ ASSERT_EQ(glGetError(), GL_NO_ERROR);
+ // Obtain a writeable pointer using either OpenGL or the Android API,
+ // then copy the test string into it.
+ if (write_hwbuffer) {
+ void* data = nullptr;
+ error = AHardwareBuffer_lock(hwbuffer,
+ AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, -1,
+ NULL, &data);
+ ASSERT_EQ(error, NO_ERROR);
+ ASSERT_TRUE(data);
+ memcpy(data, test_string.c_str(), test_string.size());
+ error = AHardwareBuffer_unlock(hwbuffer, nullptr);
+ ASSERT_EQ(error, NO_ERROR);
+ } else {
+ void* data =
+ glMapBufferRange(GL_UNIFORM_BUFFER, 0, bufsize,
+ GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT_EXT);
+ ASSERT_EQ(glGetError(), GL_NO_ERROR);
+ ASSERT_TRUE(data);
+ memcpy(data, test_string.c_str(), test_string.size());
+ glUnmapBuffer(GL_UNIFORM_BUFFER);
+ ASSERT_EQ(glGetError(), GL_NO_ERROR);
+ }
+ // Obtain a readable pointer and verify the data.
+ void* data = glMapBufferRange(GL_UNIFORM_BUFFER, 0, bufsize, GL_MAP_READ_BIT);
+ ASSERT_TRUE(data);
+ ASSERT_EQ(strncmp(static_cast<char*>(data), test_string.c_str(),
+ test_string.size()), 0);
+ glUnmapBuffer(GL_UNIFORM_BUFFER);
+ ASSERT_EQ(glGetError(), GL_NO_ERROR);
+ AHardwareBuffer_release(hwbuffer);
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_android_vr_cts_VrExtensionBehaviorTest_nativeTestExternalBuffer(
+ JNIEnv* env, jclass /* unused */) {
+ // First, check for EXT_external_buffer in the extension string.
+ auto exts = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
+ ASSERT_TRUE(exts && strstr(exts, "GL_EXT_external_buffer"));
+ // Next, load entry points provided by extensions.
+ LOAD_PROC(glBufferStorageExternalEXT, PFNGLBUFFERSTORAGEEXTERNALEXTPROC);
+ ASSERT_NE(glBufferStorageExternalEXT, nullptr);
+ LOAD_PROC(glMapBufferRange, PFNGLMAPBUFFERRANGEPROC);
+ ASSERT_NE(glMapBufferRange, nullptr);
+ LOAD_PROC(glUnmapBuffer, PFNGLUNMAPBUFFERPROC);
+ ASSERT_NE(glUnmapBuffer, nullptr);
+ const uint64_t usage = AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
+ AHARDWAREBUFFER_USAGE_CPU_READ_RARELY |
+ AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER |
+ AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA;
+ const std::string test_string = "Hello, world.";
+ // First try writing to the buffer using OpenGL, then try writing to it via
+ // the AHardwareBuffer API.
+ testExternalBuffer(env, usage, false, test_string);
+ testExternalBuffer(env, usage, true, test_string);
+}
diff --git a/tests/vr/src/android/vr/cts/RendererProtectedTexturesTest.java b/tests/vr/src/android/vr/cts/RendererProtectedTexturesTest.java
index 8b0788b..2a24ec0 100644
--- a/tests/vr/src/android/vr/cts/RendererProtectedTexturesTest.java
+++ b/tests/vr/src/android/vr/cts/RendererProtectedTexturesTest.java
@@ -32,7 +32,7 @@
+ "} \n";
private String fragmentShaderCode = "precision mediump float; \n"
- + "sampler2D protectedTexture;\n"
+ + "uniform sampler2D protectedTexture;\n"
+ "void main(){ \n"
+ " gl_FragColor = texture2D(protectedTexture, vec2(0.76953125, 0.22265625)); \n"
+ "} \n";
@@ -72,4 +72,3 @@
GLES20.glUniform1i(loc, 2);
}
}
-
diff --git a/tests/vr/src/android/vr/cts/VrExtensionBehaviorTest.java b/tests/vr/src/android/vr/cts/VrExtensionBehaviorTest.java
index f364241..a27633a 100644
--- a/tests/vr/src/android/vr/cts/VrExtensionBehaviorTest.java
+++ b/tests/vr/src/android/vr/cts/VrExtensionBehaviorTest.java
@@ -157,6 +157,8 @@
/**
* Test that a layered EGLImage can be created and attached to a FBO.
+ * For more information, see the EGL_image_array spec:
+ * https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_EGL_image_array.txt
*/
public void testEglImageArray() throws Throwable {
mActivity = getGlEsActivity(OpenGLESActivity.RENDERER_BASIC, 0, 0, 0);
@@ -173,6 +175,25 @@
}
/**
+ * Test that an external buffer can be created, written to, and read from.
+ * For more information, see the GL_EXT_external_buffer spec:
+ * https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_external_buffer.txt
+ */
+ public void testExternalBuffer() throws Throwable {
+ mActivity = getGlEsActivity(OpenGLESActivity.RENDERER_BASIC, 0, 0, 0);
+ if (!mActivity.supportsVrHighPerformance())
+ return;
+
+ assertEquals(GLES32.GL_NO_ERROR, mActivity.glGetError());
+
+ mActivity.runOnGlThread(new Runnable() {
+ public void run() {
+ nativeTestExternalBuffer();
+ }
+ });
+ }
+
+ /**
* Runs a context priority test.
*/
private void runContextPriorityTest(int priority) throws Throwable {
@@ -201,4 +222,5 @@
}
private static native boolean nativeTestEglImageArray();
+ private static native boolean nativeTestExternalBuffer();
}