• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #undef LOG_TAG
18 #define LOG_TAG "VtsHalGraphicsAllocatorAidl_TargetTest"
19 
20 #include <aidl/Vintf.h>
21 #include <aidl/android/hardware/graphics/allocator/AllocationError.h>
22 #include <aidl/android/hardware/graphics/allocator/AllocationResult.h>
23 #include <aidl/android/hardware/graphics/allocator/IAllocator.h>
24 #include <aidl/android/hardware/graphics/common/BufferUsage.h>
25 #include <aidl/android/hardware/graphics/common/PixelFormat.h>
26 #include <aidlcommonsupport/NativeHandle.h>
27 #include <android/binder_manager.h>
28 #include <android/dlext.h>
29 #include <android/hardware/graphics/mapper/4.0/IMapper.h>
30 #include <android/hardware/graphics/mapper/IMapper.h>
31 #include <dlfcn.h>
32 #include <gtest/gtest.h>
33 #include <hidl/GtestPrinter.h>
34 #include <hidl/ServiceManagement.h>
35 #include <hwui/Bitmap.h>
36 #include <renderthread/EglManager.h>
37 #include <utils/GLUtils.h>
38 #include <vndk/hardware_buffer.h>
39 #include <vndksupport/linker.h>
40 #include <initializer_list>
41 #include <optional>
42 #include <string>
43 #include <tuple>
44 
45 using namespace aidl::android::hardware::graphics::allocator;
46 using namespace aidl::android::hardware::graphics::common;
47 using namespace android;
48 using namespace android::hardware;
49 using IMapper4 = android::hardware::graphics::mapper::V4_0::IMapper;
50 using Error = android::hardware::graphics::mapper::V4_0::Error;
51 using android::hardware::graphics::mapper::V4_0::BufferDescriptor;
52 using android::uirenderer::AutoEglImage;
53 using android::uirenderer::AutoGLFramebuffer;
54 using android::uirenderer::AutoSkiaGlTexture;
55 using android::uirenderer::renderthread::EglManager;
56 
57 typedef AIMapper_Error (*AIMapper_loadIMapperFn)(AIMapper* _Nullable* _Nonnull outImplementation);
58 
operator |(BufferUsage lhs,BufferUsage rhs)59 inline BufferUsage operator|(BufferUsage lhs, BufferUsage rhs) {
60     using T = std::underlying_type_t<BufferUsage>;
61     return static_cast<BufferUsage>(static_cast<T>(lhs) | static_cast<T>(rhs));
62 }
63 
operator |=(BufferUsage & lhs,BufferUsage rhs)64 inline BufferUsage& operator|=(BufferUsage& lhs, BufferUsage rhs) {
65     lhs = lhs | rhs;
66     return lhs;
67 }
68 
convert(const BufferDescriptorInfo & info)69 static IMapper4::BufferDescriptorInfo convert(const BufferDescriptorInfo& info) {
70     return IMapper4::BufferDescriptorInfo{
71             .name{reinterpret_cast<const char*>(info.name.data())},
72             .width = static_cast<uint32_t>(info.width),
73             .height = static_cast<uint32_t>(info.height),
74             .layerCount = static_cast<uint32_t>(info.layerCount),
75             .format = static_cast<hardware::graphics::common::V1_2::PixelFormat>(info.format),
76             .usage = static_cast<uint64_t>(info.usage),
77             .reservedSize = 0,
78     };
79 }
80 
81 class GraphicsTestsBase;
82 
83 class BufferHandle {
84     GraphicsTestsBase& mTestBase;
85     native_handle_t* mRawHandle;
86     bool mImported = false;
87     uint32_t mStride;
88     const BufferDescriptorInfo mInfo;
89 
90     BufferHandle(const BufferHandle&) = delete;
91     void operator=(const BufferHandle&) = delete;
92 
93   public:
BufferHandle(GraphicsTestsBase & testBase,native_handle_t * handle,bool imported,uint32_t stride,const BufferDescriptorInfo & info)94     BufferHandle(GraphicsTestsBase& testBase, native_handle_t* handle, bool imported,
95                  uint32_t stride, const BufferDescriptorInfo& info)
96         : mTestBase(testBase),
97           mRawHandle(handle),
98           mImported(imported),
99           mStride(stride),
100           mInfo(info) {}
101 
102     ~BufferHandle();
103 
stride() const104     uint32_t stride() const { return mStride; }
105 
describe() const106     AHardwareBuffer_Desc describe() const {
107         return {
108                 .width = static_cast<uint32_t>(mInfo.width),
109                 .height = static_cast<uint32_t>(mInfo.height),
110                 .layers = static_cast<uint32_t>(mInfo.layerCount),
111                 .format = static_cast<uint32_t>(mInfo.format),
112                 .usage = static_cast<uint64_t>(mInfo.usage),
113                 .stride = stride(),
114                 .rfu0 = 0,
115                 .rfu1 = 0,
116         };
117     }
118 
createAHardwareBuffer() const119     AHardwareBuffer* createAHardwareBuffer() const {
120         auto desc = describe();
121         AHardwareBuffer* buffer = nullptr;
122         int err = AHardwareBuffer_createFromHandle(
123                 &desc, mRawHandle, AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, &buffer);
124         EXPECT_EQ(0, err) << "Failed to AHardwareBuffer_createFromHandle";
125         return err ? nullptr : buffer;
126     }
127 };
128 
129 class GraphicsTestsBase {
130   private:
131     friend class BufferHandle;
132     int32_t mIAllocatorVersion = 1;
133     std::shared_ptr<IAllocator> mAllocator;
134     sp<IMapper4> mMapper4;
135     AIMapper* mAIMapper = nullptr;
136 
137   protected:
Initialize(std::string allocatorService)138     void Initialize(std::string allocatorService) {
139         mAllocator = IAllocator::fromBinder(
140                 ndk::SpAIBinder(AServiceManager_checkService(allocatorService.c_str())));
141         ASSERT_TRUE(mAllocator->getInterfaceVersion(&mIAllocatorVersion).isOk());
142         if (mIAllocatorVersion >= 2) {
143             std::string mapperSuffix;
144             auto status = mAllocator->getIMapperLibrarySuffix(&mapperSuffix);
145             ASSERT_TRUE(status.isOk());
146             std::string lib_name = "mapper." + mapperSuffix + ".so";
147             void* so = AServiceManager_openDeclaredPassthroughHal("mapper", mapperSuffix.c_str(),
148                                                                   RTLD_LOCAL | RTLD_NOW);
149             ASSERT_NE(nullptr, so) << "Failed to load " << lib_name;
150             auto loadIMapper = (AIMapper_loadIMapperFn)dlsym(so, "AIMapper_loadIMapper");
151             ASSERT_NE(nullptr, loadIMapper) << "AIMapper_locaIMapper missing from " << lib_name;
152             ASSERT_EQ(AIMAPPER_ERROR_NONE, loadIMapper(&mAIMapper));
153             ASSERT_NE(mAIMapper, nullptr);
154         } else {
155             // Don't have IMapper 5, fall back to IMapper 4
156             mMapper4 = IMapper4::getService();
157             ASSERT_NE(nullptr, mMapper4.get()) << "failed to get mapper service";
158             ASSERT_FALSE(mMapper4->isRemote()) << "mapper is not in passthrough mode";
159         }
160 
161         ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
162     }
163 
164   private:
createDescriptor(const BufferDescriptorInfo & descriptorInfo,bool raise_failure)165     std::optional<BufferDescriptor> createDescriptor(const BufferDescriptorInfo& descriptorInfo,
166                                                      bool raise_failure) {
167         std::optional<BufferDescriptor> descriptor;
168         mMapper4->createDescriptor(
169                 convert(descriptorInfo), [&](const auto& tmpError, const auto& tmpDescriptor) {
170                     if (raise_failure) {
171                         ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
172                     }
173 
174                     if (tmpError != Error::NONE) {
175                         return;
176                     }
177 
178                     descriptor = tmpDescriptor;
179                 });
180 
181         return descriptor;
182     }
183 
184   public:
allocate(const BufferDescriptorInfo & descriptorInfo,bool raise_failure=true)185     std::unique_ptr<BufferHandle> allocate(const BufferDescriptorInfo& descriptorInfo,
186                                            bool raise_failure = true) {
187         AllocationResult result;
188         ::ndk::ScopedAStatus status;
189         if (mIAllocatorVersion >= 2) {
190             status = mAllocator->allocate2(descriptorInfo, 1, &result);
191         } else {
192             auto descriptor = createDescriptor(descriptorInfo, raise_failure);
193             if (!descriptor.has_value()) {
194                 return nullptr;
195             }
196 
197             if (::testing::Test::HasFatalFailure()) {
198                 return nullptr;
199             }
200 #pragma clang diagnostic push
201 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
202             status = mAllocator->allocate(descriptor.value(), 1, &result);
203 #pragma clang diagnostic pop  // deprecation
204         }
205         if (!status.isOk()) {
206             status_t error = status.getExceptionCode();
207             if (error == EX_SERVICE_SPECIFIC) {
208                 error = status.getServiceSpecificError();
209                 EXPECT_NE(OK, error) << "Failed to set error properly";
210             } else {
211                 EXPECT_EQ(OK, error) << "Allocation transport failure";
212             }
213             return nullptr;
214         } else {
215             return std::make_unique<BufferHandle>(*this, dupFromAidl(result.buffers[0]), false,
216                                                   result.stride, descriptorInfo);
217         }
218     }
219 
isSupported(const BufferDescriptorInfo & descriptorInfo)220     bool isSupported(const BufferDescriptorInfo& descriptorInfo) {
221         bool ret = false;
222         if (mIAllocatorVersion >= 2) {
223             EXPECT_TRUE(mAllocator->isSupported(descriptorInfo, &ret).isOk());
224         } else {
225             EXPECT_TRUE(mMapper4->isSupported(convert(descriptorInfo),
226                                               [&](auto error, bool supported) {
227                                                   ASSERT_EQ(Error::NONE, error);
228                                                   ret = supported;
229                                               })
230                                 .isOk());
231         }
232         return ret;
233     }
234 
allocatorVersion() const235     int32_t allocatorVersion() const { return mIAllocatorVersion; }
236 };
237 
~BufferHandle()238 BufferHandle::~BufferHandle() {
239     if (mRawHandle == nullptr) return;
240 
241     if (mImported) {
242         if (mTestBase.mAIMapper) {
243             AIMapper_Error error = mTestBase.mAIMapper->v5.freeBuffer(mRawHandle);
244             EXPECT_EQ(AIMAPPER_ERROR_NONE, error);
245         } else {
246             Error error = mTestBase.mMapper4->freeBuffer(mRawHandle);
247             EXPECT_EQ(Error::NONE, error) << "failed to free buffer " << mRawHandle;
248         }
249     } else {
250         native_handle_close(mRawHandle);
251         native_handle_delete(mRawHandle);
252     }
253 }
254 
255 class GraphicsAllocatorAidlTests : public GraphicsTestsBase,
256                                    public ::testing::TestWithParam<std::string> {
257   public:
SetUp()258     void SetUp() override { Initialize(GetParam()); }
259 
TearDown()260     void TearDown() override {}
261 };
262 
263 struct FlushMethod {
264     std::string name;
265     std::function<void(EglManager&)> func;
266 };
267 
268 class GraphicsFrontBufferTests
269     : public GraphicsTestsBase,
270       public ::testing::TestWithParam<std::tuple<std::string, FlushMethod>> {
271   private:
272     EglManager eglManager;
273     std::function<void(EglManager&)> flush;
274 
275   public:
SetUp()276     void SetUp() override {
277         Initialize(std::get<0>(GetParam()));
278         flush = std::get<1>(GetParam()).func;
279         eglManager.initialize();
280     }
281 
TearDown()282     void TearDown() override { eglManager.destroy(); }
283 
fillWithGpu(AHardwareBuffer * buffer,float red,float green,float blue,float alpha)284     void fillWithGpu(AHardwareBuffer* buffer, float red, float green, float blue, float alpha) {
285         EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(buffer);
286         AutoEglImage eglImage(eglManager.eglDisplay(), clientBuffer);
287         AutoSkiaGlTexture glTexture;
288         AutoGLFramebuffer glFbo;
289         glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage.image);
290         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
291                                glTexture.mTexture, 0);
292 
293         AHardwareBuffer_Desc desc;
294         AHardwareBuffer_describe(buffer, &desc);
295         glViewport(0, 0, desc.width, desc.height);
296         glDisable(GL_STENCIL_TEST);
297         glDisable(GL_SCISSOR_TEST);
298         glClearColor(red, green, blue, alpha);
299         glClear(GL_COLOR_BUFFER_BIT);
300         flush(eglManager);
301     }
302 
fillWithGpu(AHardwareBuffer * buffer,uint32_t color)303     void fillWithGpu(AHardwareBuffer* buffer, /*RGBA*/ uint32_t color) {
304         // Keep it simple for now
305         static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__);
306         float a = float((color >> 24) & 0xff) / 255.0f;
307         float b = float((color >> 16) & 0xff) / 255.0f;
308         float g = float((color >> 8) & 0xff) / 255.0f;
309         float r = float((color)&0xff) / 255.0f;
310         fillWithGpu(buffer, r, g, b, a);
311     }
312 };
313 
TEST_P(GraphicsAllocatorAidlTests,CanAllocate)314 TEST_P(GraphicsAllocatorAidlTests, CanAllocate) {
315     auto buffer = allocate({
316             .name = {"CPU_8888"},
317             .width = 64,
318             .height = 64,
319             .layerCount = 1,
320             .format = PixelFormat::RGBA_8888,
321             .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
322             .reservedSize = 0,
323     });
324     ASSERT_NE(nullptr, buffer.get());
325     EXPECT_GE(buffer->stride(), 64);
326 }
327 
TEST_P(GraphicsAllocatorAidlTests,RejectsUnknownUsages)328 TEST_P(GraphicsAllocatorAidlTests, RejectsUnknownUsages) {
329     if (allocatorVersion() < 2) {
330         GTEST_SKIP() << "Must be version 2+";
331         return;
332     }
333 
334     constexpr auto FirstInvalidV2Usage = static_cast<BufferUsage>(1LL << 33);
335 
336     BufferUsage invalidUsage;
337     if (allocatorVersion() == 2) {
338         invalidUsage = FirstInvalidV2Usage;
339     } else {
340         GTEST_FAIL() << "Unknown version " << allocatorVersion();
341     }
342 
343     BufferDescriptorInfo info{
344             .name = {"CPU_8888"},
345             .width = 64,
346             .height = 64,
347             .layerCount = 1,
348             .format = PixelFormat::RGBA_8888,
349             .usage = BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
350             .reservedSize = 0,
351     };
352 
353     // First make sure we can allocate a known usage buffer as expected
354     EXPECT_TRUE(isSupported(info));
355     EXPECT_TRUE(allocate(info));
356 
357     // Now add the unknown bit and verify it's rejected
358     info.usage |= invalidUsage;
359     EXPECT_FALSE(isSupported(info)) << "isSupported() returned true for unknown-to-HAL usage";
360     EXPECT_FALSE(allocate(info)) << "allocate succeeded for unknown-to-HAL usage";
361 }
362 
TEST_P(GraphicsAllocatorAidlTests,RejectsUnknownOptions)363 TEST_P(GraphicsAllocatorAidlTests, RejectsUnknownOptions) {
364     if (allocatorVersion() < 2) {
365         GTEST_SKIP() << "Must be version 2+";
366         return;
367     }
368 
369     BufferDescriptorInfo info{
370             .name = {"CPU_8888"},
371             .width = 64,
372             .height = 64,
373             .layerCount = 1,
374             .format = PixelFormat::RGBA_8888,
375             .usage = BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
376             .reservedSize = 0,
377     };
378     info.additionalOptions.push_back({"android.hardware.graphics.common.NotARealOption", 1});
379 
380     EXPECT_FALSE(isSupported(info)) << "isSupported() returned true for unknown-to-HAL option";
381     EXPECT_FALSE(allocate(info)) << "allocate succeeded for unknown-to-HAL option";
382 }
383 
TEST_P(GraphicsFrontBufferTests,FrontBufferGpuToCpu)384 TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToCpu) {
385     BufferDescriptorInfo info{
386             .name = {"CPU_8888"},
387             .width = 64,
388             .height = 64,
389             .layerCount = 1,
390             .format = PixelFormat::RGBA_8888,
391             .usage = BufferUsage::GPU_RENDER_TARGET | BufferUsage::CPU_READ_OFTEN |
392                      BufferUsage::FRONT_BUFFER,
393             .reservedSize = 0,
394     };
395     const bool supported = isSupported(info);
396     auto buffer = allocate(info, /*raise_failure=*/supported);
397     if (!supported) {
398         ASSERT_EQ(nullptr, buffer.get())
399                 << "Allocation succeeded, but IMapper::isSupported was false";
400         GTEST_SKIP();
401     } else {
402         ASSERT_NE(nullptr, buffer.get()) << "Allocation failed, but IMapper::isSupported was true";
403     }
404 
405     AHardwareBuffer* ahb = buffer->createAHardwareBuffer();
406     ASSERT_NE(nullptr, ahb);
407 
408     // We draw 3 times with 3 different colors to ensure the flush is consistently flushing.
409     // Particularly for glFlush() there's occasions where it seems something triggers a flush
410     // to happen even though glFlush itself isn't consistently doing so, but for FRONT_BUFFER
411     // bound buffers it is supposed to consistently flush.
412     for (uint32_t color : {0xFF0000FFu, 0x00FF00FFu, 0x0000FFFFu}) {
413         fillWithGpu(ahb, color);
414         uint32_t* addr;
415         ASSERT_EQ(0, AHardwareBuffer_lock(ahb, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, -1, nullptr,
416                                           (void**)&addr));
417         // Spot check a few pixels
418         EXPECT_EQ(color, addr[0]);
419         EXPECT_EQ(color, addr[32 + (32 * buffer->stride())]);
420         AHardwareBuffer_unlock(ahb, nullptr);
421     }
422 
423     AHardwareBuffer_release(ahb);
424 }
425 
TEST_P(GraphicsFrontBufferTests,FrontBufferGpuToGpu)426 TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToGpu) {
427     BufferDescriptorInfo info{
428             .name = {"CPU_8888"},
429             .width = 64,
430             .height = 64,
431             .layerCount = 1,
432             .format = PixelFormat::RGBA_8888,
433             .usage = BufferUsage::GPU_RENDER_TARGET | BufferUsage::GPU_TEXTURE |
434                      BufferUsage::FRONT_BUFFER,
435             .reservedSize = 0,
436     };
437     const bool supported = isSupported(info);
438     auto buffer = allocate(info, /*raise_failure=*/supported);
439     if (!supported) {
440         ASSERT_EQ(nullptr, buffer.get())
441                 << "Allocation succeeded, but IMapper::isSupported was false";
442         GTEST_SKIP();
443     } else {
444         ASSERT_NE(nullptr, buffer.get()) << "Allocation failed, but IMapper::isSupported was true";
445     }
446 
447     AHardwareBuffer* ahb = buffer->createAHardwareBuffer();
448     ASSERT_NE(nullptr, ahb);
449 
450     // We draw 3 times with 3 different colors to ensure the flush is consistently flushing.
451     // Particularly for glFlush() there's occasions where it seems something triggers a flush
452     // to happen even though glFlush itself isn't consistently doing so, but for FRONT_BUFFER
453     // bound buffers it is supposed to consistently flush.
454     for (uint32_t color : {0xFF0000FFu, 0x00FF00FFu, 0x0000FFFFu}) {
455         fillWithGpu(ahb, color);
456         sk_sp<Bitmap> hwBitmap = Bitmap::createFrom(ahb, SkColorSpace::MakeSRGB());
457         SkBitmap cpuBitmap = hwBitmap->getSkBitmap();
458         // Spot check a few pixels
459         EXPECT_EQ(color, *cpuBitmap.getAddr32(0, 0));
460         EXPECT_EQ(color, *cpuBitmap.getAddr32(16, 30));
461     }
462 
463     AHardwareBuffer_release(ahb);
464 }
465 
466 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsAllocatorAidlTests);
467 INSTANTIATE_TEST_CASE_P(PerInstance, GraphicsAllocatorAidlTests,
468                         testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
469                         PrintInstanceNameToString);
470 
471 const auto FlushMethodsValues = testing::Values(
__anon62538b1f0302(EglManager&) 472         FlushMethod{"glFinish", [](EglManager&) { glFinish(); }},
473         FlushMethod{"glFlush",
__anon62538b1f0402(EglManager&) 474                     [](EglManager&) {
475                         glFlush();
476                         // Since the goal is to verify that glFlush() actually flushes, we can't
477                         // wait on any sort of fence since that will change behavior So instead we
478                         // just sleep & hope
479                         sleep(1);
480                     }},
__anon62538b1f0502(EglManager& eglManager) 481         FlushMethod{"eglClientWaitSync", [](EglManager& eglManager) {
482                         EGLDisplay display = eglManager.eglDisplay();
483                         EGLSyncKHR fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
484                         eglClientWaitSyncKHR(display, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
485                                              EGL_FOREVER_KHR);
486                         eglDestroySyncKHR(display, fence);
487                     }});
488 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsFrontBufferTests);
489 INSTANTIATE_TEST_CASE_P(
490         PerInstance, GraphicsFrontBufferTests,
491         testing::Combine(testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
492                          FlushMethodsValues),
__anon62538b1f0602(auto info) 493         [](auto info) -> std::string {
494             std::string name = std::to_string(info.index) + "/" + std::get<1>(info.param).name;
495             return Sanitize(name);
496         });
497