Edit

kc3-lang/angle/src/tests/gl_tests/ExternalBufferTest.cpp

Branch :

  • Show log

    Commit

  • Author : Mohan Maiya
    Date : 2021-03-20 09:39:09
    Hash : 7fe44a53
    Message : Vulkan: Don't acquire new BufferHelper for external buffers EXT_external_buffer spec - This extension allows the data store for an immutable buffer to be sourced from an external EGLClientBuffer, allowing sharing of EGL client buffers across APIs, across processes, and across different processing cores such as the GPU, CPU, and DSP. The intent is for a single backing memory to be reused across various processes and processors. Ensure that a glBuffer backed by external memory does not orphan the memory when glBuffer APIs like glBufferSubData or glMapBufferRangeEXT modify the glBuffer. Bug: angleproject:4380 Bug: angleproject:5073 Tests: ExternalBufferTestES31.*DoesNotCauseOrphaning*Vulkan Change-Id: I4e88f80d93ee1ba1208378121412926351d10af8 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2776192 Commit-Queue: Mohan Maiya <m.maiya@samsung.com> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/tests/gl_tests/ExternalBufferTest.cpp
  • //
    // 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 <android/hardware_buffer.h>
    #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<GLubyte> 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<GLubyte> 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<uint8_t *>(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<GLubyte> 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<GLubyte> 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<GLubyte> 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<uint8_t *>(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<GLubyte> 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<uint32_t *>(lockAndroidHardwareBuffer(aHardwareBuffer));
    
        for (uint32_t i = 0; i < (kBufferSize / sizeof(uint32_t)); ++i)
        {
            EXPECT_EQ(data[i], static_cast<uint32_t>(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<GLubyte> 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<uint8_t *>(
            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<GLubyte> 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<GLubyte> 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<uint8_t *>(
            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<GLubyte> 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<uint8_t *>(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