// // Copyright 2020 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // ExternalBufferTest: // Tests the correctness of external buffer ext extension. // #include "test_utils/ANGLETest.h" #include "test_utils/gl_raii.h" #include "util/EGLWindow.h" #include "common/android_util.h" #if defined(ANGLE_PLATFORM_ANDROID) && __ANDROID_API__ >= 26 # define ANGLE_AHARDWARE_BUFFER_SUPPORT // NDK header file for access to Android Hardware Buffers # include #endif namespace angle { class ExternalBufferTestES31 : public ANGLETest { protected: ExternalBufferTestES31() { setWindowWidth(16); setWindowHeight(16); setConfigRedBits(8); setConfigGreenBits(8); setConfigBlueBits(8); setConfigAlphaBits(8); setConfigDepthBits(24); } AHardwareBuffer *createAndroidHardwareBuffer(size_t size, const GLubyte *data) { #if defined(ANGLE_AHARDWARE_BUFFER_SUPPORT) // The height and width are number of pixels of size format AHardwareBuffer_Desc aHardwareBufferDescription = {}; aHardwareBufferDescription.width = size; aHardwareBufferDescription.height = 1; aHardwareBufferDescription.layers = 1; aHardwareBufferDescription.format = AHARDWAREBUFFER_FORMAT_BLOB; aHardwareBufferDescription.usage = AHARDWAREBUFFER_USAGE_CPU_READ_RARELY | AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER; aHardwareBufferDescription.stride = 0; // Allocate memory from Android Hardware Buffer AHardwareBuffer *aHardwareBuffer = nullptr; EXPECT_EQ(0, AHardwareBuffer_allocate(&aHardwareBufferDescription, &aHardwareBuffer)); void *mappedMemory = nullptr; EXPECT_EQ(0, AHardwareBuffer_lock(aHardwareBuffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY, -1, nullptr, &mappedMemory)); // Need to grab the stride the implementation might have enforced AHardwareBuffer_describe(aHardwareBuffer, &aHardwareBufferDescription); memcpy(mappedMemory, data, size); EXPECT_EQ(0, AHardwareBuffer_unlock(aHardwareBuffer, nullptr)); return aHardwareBuffer; #else return nullptr; #endif // ANGLE_PLATFORM_ANDROID } void destroyAndroidHardwareBuffer(AHardwareBuffer *aHardwareBuffer) { #if defined(ANGLE_AHARDWARE_BUFFER_SUPPORT) AHardwareBuffer_release(aHardwareBuffer); #endif } void *lockAndroidHardwareBuffer(AHardwareBuffer *aHardwareBuffer) { void *data = nullptr; #if defined(ANGLE_AHARDWARE_BUFFER_SUPPORT) EXPECT_EQ(0, AHardwareBuffer_lock(aHardwareBuffer, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, -1, nullptr, &data)); #endif return data; } void unlockAndroidHardwareBuffer(AHardwareBuffer *aHardwareBuffer) { #if defined(ANGLE_AHARDWARE_BUFFER_SUPPORT) AHardwareBuffer_unlock(aHardwareBuffer, nullptr); #endif } }; // Testing subdata update with external buffer from AHB TEST_P(ExternalBufferTestES31, BufferSubData) { ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_external_buffer") || !IsGLExtensionEnabled("GL_EXT_buffer_storage")); constexpr uint8_t kBufferSize = 16; std::vector initData(kBufferSize, 0xA); // Create the Image AHardwareBuffer *aHardwareBuffer; constexpr GLbitfield kFlags = GL_DYNAMIC_STORAGE_BIT_EXT; aHardwareBuffer = createAndroidHardwareBuffer(kBufferSize, initData.data()); GLBuffer buffer; glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer); glBufferStorageExternalEXT(GL_SHADER_STORAGE_BUFFER, 0, kBufferSize, eglGetNativeClientBufferANDROID(aHardwareBuffer), kFlags); ASSERT_GL_NO_ERROR(); std::vector expectedData(kBufferSize, 0xFF); glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, kBufferSize, expectedData.data()); glFinish(); ASSERT_GL_NO_ERROR(); // Inspect the data written into the buffer using CPU access. uint8_t *data = static_cast(lockAndroidHardwareBuffer(aHardwareBuffer)); for (uint32_t i = 0; i < kBufferSize; ++i) { EXPECT_EQ(data[i], 0xFF); } unlockAndroidHardwareBuffer(aHardwareBuffer); glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); // Delete the source AHB destroyAndroidHardwareBuffer(aHardwareBuffer); } // Verify that subdata updates to an external buffer backed by an AHB doesn't orphan the AHB TEST_P(ExternalBufferTestES31, SubDataDoesNotCauseOrphaning) { ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_external_buffer") || !IsGLExtensionEnabled("GL_EXT_buffer_storage")); constexpr uint8_t kBufferSize = 16; std::vector initData(kBufferSize, 0xA); // Create the AHB AHardwareBuffer *aHardwareBuffer; constexpr GLbitfield kFlags = GL_DYNAMIC_STORAGE_BIT_EXT; aHardwareBuffer = createAndroidHardwareBuffer(kBufferSize, initData.data()); // Create externalBuffer GLBuffer externalBuffer; glBindBuffer(GL_SHADER_STORAGE_BUFFER, externalBuffer); glBufferStorageExternalEXT(GL_SHADER_STORAGE_BUFFER, 0, kBufferSize, eglGetNativeClientBufferANDROID(aHardwareBuffer), kFlags); ASSERT_GL_NO_ERROR(); // Create a copy read buffer std::vector copyReadBufferData(kBufferSize, 0xB); GLBuffer copyReadBuffer; glBindBuffer(GL_COPY_READ_BUFFER, copyReadBuffer); glBufferData(GL_COPY_READ_BUFFER, kBufferSize, copyReadBufferData.data(), GL_STATIC_READ); ASSERT_GL_NO_ERROR(); // Copy from copyReadBuffer to externalBuffer glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_SHADER_STORAGE_BUFFER, 0, 0, kBufferSize); ASSERT_GL_NO_ERROR(); // Update externalBuffer std::vector expectedData(kBufferSize, 0xFF); glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, kBufferSize, expectedData.data()); glFinish(); ASSERT_GL_NO_ERROR(); // Inspect the data written into the AHB, through externalBuffer, using CPU access. uint8_t *data = static_cast(lockAndroidHardwareBuffer(aHardwareBuffer)); for (uint32_t i = 0; i < kBufferSize; ++i) { EXPECT_EQ(data[i], 0xFF); } unlockAndroidHardwareBuffer(aHardwareBuffer); glBindBuffer(GL_COPY_READ_BUFFER, 0); glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); // Delete the source AHB destroyAndroidHardwareBuffer(aHardwareBuffer); } // Testing dispatch compute shader external from source AHB TEST_P(ExternalBufferTestES31, DispatchCompute) { ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_external_buffer") || !IsGLExtensionEnabled("GL_EXT_buffer_storage")); constexpr char kCS[] = R"(#version 310 es layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; layout(std430, binding=0) buffer Output { uint data[]; } bOutput; void main() { bOutput.data[gl_GlobalInvocationID.x] = gl_GlobalInvocationID.x * 3u; } )"; constexpr uint8_t kBufferSize = 16 * 4; std::vector initData(kBufferSize, 0xA); // Create the Image AHardwareBuffer *aHardwareBuffer; constexpr GLbitfield kFlags = GL_MAP_READ_BIT; aHardwareBuffer = createAndroidHardwareBuffer(kBufferSize, initData.data()); GLBuffer buffer; glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer); glBufferStorageExternalEXT(GL_SHADER_STORAGE_BUFFER, 0, kBufferSize, eglGetNativeClientBufferANDROID(aHardwareBuffer), kFlags); ASSERT_GL_NO_ERROR(); GLProgram program; program.makeCompute(kCS); ASSERT_NE(program.get(), 0U); ASSERT_GL_NO_ERROR(); glUseProgram(program); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffer); glDispatchCompute(kBufferSize, 1, 1); glFinish(); ASSERT_GL_NO_ERROR(); // Inspect the data written into the buffer using CPU access. uint32_t *data = static_cast(lockAndroidHardwareBuffer(aHardwareBuffer)); for (uint32_t i = 0; i < (kBufferSize / sizeof(uint32_t)); ++i) { EXPECT_EQ(data[i], static_cast(i * 3)); } unlockAndroidHardwareBuffer(aHardwareBuffer); glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); // Delete the source AHB destroyAndroidHardwareBuffer(aHardwareBuffer); } // Test interaction between GL_OES_mapbuffer and GL_EXT_external_buffer extensions. TEST_P(ExternalBufferTestES31, MapBuffer) { ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_external_buffer") || !IsGLExtensionEnabled("GL_EXT_buffer_storage") || !IsGLExtensionEnabled("GL_EXT_map_buffer_range")); constexpr uint8_t kBufferSize = 16; std::vector initData(kBufferSize, 0xFF); // Create the AHB AHardwareBuffer *aHardwareBuffer; constexpr GLbitfield kFlags = (GL_MAP_READ_BIT_EXT | GL_MAP_WRITE_BIT_EXT); aHardwareBuffer = createAndroidHardwareBuffer(kBufferSize, initData.data()); GLBuffer buffer; glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer); glBufferStorageExternalEXT(GL_SHADER_STORAGE_BUFFER, 0, kBufferSize, eglGetNativeClientBufferANDROID(aHardwareBuffer), kFlags); ASSERT_GL_NO_ERROR(); // Inspect the data written into the buffer using CPU access. uint8_t *data = static_cast( glMapBufferRangeEXT(GL_SHADER_STORAGE_BUFFER, 0, kBufferSize, GL_MAP_READ_BIT_EXT)); ASSERT_GL_NO_ERROR(); for (uint32_t i = 0; i < kBufferSize; ++i) { EXPECT_EQ(data[i], 0xFF); } glUnmapBufferOES(GL_SHADER_STORAGE_BUFFER); glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); // Delete the source AHB destroyAndroidHardwareBuffer(aHardwareBuffer); } // Verify that mapping an external buffer backed by an AHB doesn't orphan the AHB TEST_P(ExternalBufferTestES31, MapBufferDoesNotCauseOrphaning) { ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_external_buffer") || !IsGLExtensionEnabled("GL_EXT_buffer_storage") || !IsGLExtensionEnabled("GL_EXT_map_buffer_range")); constexpr uint8_t kBufferSize = 16; std::vector initData(kBufferSize, 0xA); // Create the AHB AHardwareBuffer *aHardwareBuffer; constexpr GLbitfield kFlags = (GL_MAP_READ_BIT_EXT | GL_MAP_WRITE_BIT_EXT | GL_DYNAMIC_STORAGE_BIT_EXT); aHardwareBuffer = createAndroidHardwareBuffer(kBufferSize, initData.data()); GLBuffer buffer; glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer); glBufferStorageExternalEXT(GL_SHADER_STORAGE_BUFFER, 0, kBufferSize, eglGetNativeClientBufferANDROID(aHardwareBuffer), kFlags); ASSERT_GL_NO_ERROR(); // Create a copy read buffer std::vector copyReadBufferData(kBufferSize, 0xB); GLBuffer copyReadBuffer; glBindBuffer(GL_COPY_READ_BUFFER, copyReadBuffer); glBufferData(GL_COPY_READ_BUFFER, kBufferSize, copyReadBufferData.data(), GL_STATIC_READ); ASSERT_GL_NO_ERROR(); // Copy from copyReadBuffer to externalBuffer glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_SHADER_STORAGE_BUFFER, 0, 0, kBufferSize); ASSERT_GL_NO_ERROR(); // Inspect the data written into the buffer using map buffer API. constexpr GLbitfield kMapFlags = (GL_MAP_WRITE_BIT_EXT | GL_MAP_INVALIDATE_BUFFER_BIT); uint8_t *mapData = static_cast( glMapBufferRangeEXT(GL_SHADER_STORAGE_BUFFER, 0, kBufferSize, kMapFlags)); ASSERT_GL_NO_ERROR(); EXPECT_NE(mapData, nullptr); glUnmapBufferOES(GL_SHADER_STORAGE_BUFFER); // Update externalBuffer std::vector expectedData(kBufferSize, 0xFF); glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, kBufferSize, expectedData.data()); glFinish(); ASSERT_GL_NO_ERROR(); // Inspect the data written into the AHB, through externalBuffer, using CPU access. uint8_t *data = static_cast(lockAndroidHardwareBuffer(aHardwareBuffer)); for (uint32_t i = 0; i < kBufferSize; ++i) { EXPECT_EQ(data[i], 0xFF); } unlockAndroidHardwareBuffer(aHardwareBuffer); glBindBuffer(GL_COPY_READ_BUFFER, 0); glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); // Delete the source AHB destroyAndroidHardwareBuffer(aHardwareBuffer); } GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ExternalBufferTestES31); ANGLE_INSTANTIATE_TEST_ES31(ExternalBufferTestES31); } // namespace angle