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)165     BufferDescriptor createDescriptor(const BufferDescriptorInfo& descriptorInfo) {
166         BufferDescriptor descriptor;
167         mMapper4->createDescriptor(
168                 convert(descriptorInfo), [&](const auto& tmpError, const auto& tmpDescriptor) {
169                     ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
170                     descriptor = tmpDescriptor;
171                 });
172 
173         return descriptor;
174     }
175 
176   public:
allocate(const BufferDescriptorInfo & descriptorInfo)177     std::unique_ptr<BufferHandle> allocate(const BufferDescriptorInfo& descriptorInfo) {
178         AllocationResult result;
179         ::ndk::ScopedAStatus status;
180         if (mIAllocatorVersion >= 2) {
181             status = mAllocator->allocate2(descriptorInfo, 1, &result);
182         } else {
183             auto descriptor = createDescriptor(descriptorInfo);
184             if (::testing::Test::HasFatalFailure()) {
185                 return nullptr;
186             }
187 #pragma clang diagnostic push
188 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
189             status = mAllocator->allocate(descriptor, 1, &result);
190 #pragma clang diagnostic pop  // deprecation
191         }
192         if (!status.isOk()) {
193             status_t error = status.getExceptionCode();
194             if (error == EX_SERVICE_SPECIFIC) {
195                 error = status.getServiceSpecificError();
196                 EXPECT_NE(OK, error) << "Failed to set error properly";
197             } else {
198                 EXPECT_EQ(OK, error) << "Allocation transport failure";
199             }
200             return nullptr;
201         } else {
202             return std::make_unique<BufferHandle>(*this, dupFromAidl(result.buffers[0]), false,
203                                                   result.stride, descriptorInfo);
204         }
205     }
206 
isSupported(const BufferDescriptorInfo & descriptorInfo)207     bool isSupported(const BufferDescriptorInfo& descriptorInfo) {
208         bool ret = false;
209         if (mIAllocatorVersion >= 2) {
210             EXPECT_TRUE(mAllocator->isSupported(descriptorInfo, &ret).isOk());
211         } else {
212             EXPECT_TRUE(mMapper4->isSupported(convert(descriptorInfo),
213                                               [&](auto error, bool supported) {
214                                                   ASSERT_EQ(Error::NONE, error);
215                                                   ret = supported;
216                                               })
217                                 .isOk());
218         }
219         return ret;
220     }
221 
allocatorVersion() const222     int32_t allocatorVersion() const { return mIAllocatorVersion; }
223 };
224 
~BufferHandle()225 BufferHandle::~BufferHandle() {
226     if (mRawHandle == nullptr) return;
227 
228     if (mImported) {
229         if (mTestBase.mAIMapper) {
230             AIMapper_Error error = mTestBase.mAIMapper->v5.freeBuffer(mRawHandle);
231             EXPECT_EQ(AIMAPPER_ERROR_NONE, error);
232         } else {
233             Error error = mTestBase.mMapper4->freeBuffer(mRawHandle);
234             EXPECT_EQ(Error::NONE, error) << "failed to free buffer " << mRawHandle;
235         }
236     } else {
237         native_handle_close(mRawHandle);
238         native_handle_delete(mRawHandle);
239     }
240 }
241 
242 class GraphicsAllocatorAidlTests : public GraphicsTestsBase,
243                                    public ::testing::TestWithParam<std::string> {
244   public:
SetUp()245     void SetUp() override { Initialize(GetParam()); }
246 
TearDown()247     void TearDown() override {}
248 };
249 
250 struct FlushMethod {
251     std::string name;
252     std::function<void(EglManager&)> func;
253 };
254 
255 class GraphicsFrontBufferTests
256     : public GraphicsTestsBase,
257       public ::testing::TestWithParam<std::tuple<std::string, FlushMethod>> {
258   private:
259     EglManager eglManager;
260     std::function<void(EglManager&)> flush;
261 
262   public:
SetUp()263     void SetUp() override {
264         Initialize(std::get<0>(GetParam()));
265         flush = std::get<1>(GetParam()).func;
266         eglManager.initialize();
267     }
268 
TearDown()269     void TearDown() override { eglManager.destroy(); }
270 
fillWithGpu(AHardwareBuffer * buffer,float red,float green,float blue,float alpha)271     void fillWithGpu(AHardwareBuffer* buffer, float red, float green, float blue, float alpha) {
272         EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(buffer);
273         AutoEglImage eglImage(eglManager.eglDisplay(), clientBuffer);
274         AutoSkiaGlTexture glTexture;
275         AutoGLFramebuffer glFbo;
276         glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage.image);
277         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
278                                glTexture.mTexture, 0);
279 
280         AHardwareBuffer_Desc desc;
281         AHardwareBuffer_describe(buffer, &desc);
282         glViewport(0, 0, desc.width, desc.height);
283         glDisable(GL_STENCIL_TEST);
284         glDisable(GL_SCISSOR_TEST);
285         glClearColor(red, green, blue, alpha);
286         glClear(GL_COLOR_BUFFER_BIT);
287         flush(eglManager);
288     }
289 
fillWithGpu(AHardwareBuffer * buffer,uint32_t color)290     void fillWithGpu(AHardwareBuffer* buffer, /*RGBA*/ uint32_t color) {
291         // Keep it simple for now
292         static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__);
293         float a = float((color >> 24) & 0xff) / 255.0f;
294         float b = float((color >> 16) & 0xff) / 255.0f;
295         float g = float((color >> 8) & 0xff) / 255.0f;
296         float r = float((color)&0xff) / 255.0f;
297         fillWithGpu(buffer, r, g, b, a);
298     }
299 };
300 
TEST_P(GraphicsAllocatorAidlTests,CanAllocate)301 TEST_P(GraphicsAllocatorAidlTests, CanAllocate) {
302     auto buffer = allocate({
303             .name = {"CPU_8888"},
304             .width = 64,
305             .height = 64,
306             .layerCount = 1,
307             .format = PixelFormat::RGBA_8888,
308             .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
309             .reservedSize = 0,
310     });
311     ASSERT_NE(nullptr, buffer.get());
312     EXPECT_GE(buffer->stride(), 64);
313 }
314 
TEST_P(GraphicsAllocatorAidlTests,RejectsUnknownUsages)315 TEST_P(GraphicsAllocatorAidlTests, RejectsUnknownUsages) {
316     if (allocatorVersion() < 2) {
317         GTEST_SKIP() << "Must be version 2+";
318         return;
319     }
320 
321     constexpr auto FirstInvalidV2Usage = static_cast<BufferUsage>(1LL << 33);
322 
323     BufferUsage invalidUsage;
324     if (allocatorVersion() == 2) {
325         invalidUsage = FirstInvalidV2Usage;
326     } else {
327         GTEST_FAIL() << "Unknown version " << allocatorVersion();
328     }
329 
330     BufferDescriptorInfo info{
331             .name = {"CPU_8888"},
332             .width = 64,
333             .height = 64,
334             .layerCount = 1,
335             .format = PixelFormat::RGBA_8888,
336             .usage = BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
337             .reservedSize = 0,
338     };
339 
340     // First make sure we can allocate a known usage buffer as expected
341     EXPECT_TRUE(isSupported(info));
342     EXPECT_TRUE(allocate(info));
343 
344     // Now add the unknown bit and verify it's rejected
345     info.usage |= invalidUsage;
346     EXPECT_FALSE(isSupported(info)) << "isSupported() returned true for unknown-to-HAL usage";
347     EXPECT_FALSE(allocate(info)) << "allocate succeeded for unknown-to-HAL usage";
348 }
349 
TEST_P(GraphicsAllocatorAidlTests,RejectsUnknownOptions)350 TEST_P(GraphicsAllocatorAidlTests, RejectsUnknownOptions) {
351     if (allocatorVersion() < 2) {
352         GTEST_SKIP() << "Must be version 2+";
353         return;
354     }
355 
356     BufferDescriptorInfo info{
357             .name = {"CPU_8888"},
358             .width = 64,
359             .height = 64,
360             .layerCount = 1,
361             .format = PixelFormat::RGBA_8888,
362             .usage = BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
363             .reservedSize = 0,
364     };
365     info.additionalOptions.push_back({"android.hardware.graphics.common.NotARealOption", 1});
366 
367     EXPECT_FALSE(isSupported(info)) << "isSupported() returned true for unknown-to-HAL option";
368     EXPECT_FALSE(allocate(info)) << "allocate succeeded for unknown-to-HAL option";
369 }
370 
TEST_P(GraphicsFrontBufferTests,FrontBufferGpuToCpu)371 TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToCpu) {
372     BufferDescriptorInfo info{
373             .name = {"CPU_8888"},
374             .width = 64,
375             .height = 64,
376             .layerCount = 1,
377             .format = PixelFormat::RGBA_8888,
378             .usage = BufferUsage::GPU_RENDER_TARGET | BufferUsage::CPU_READ_OFTEN |
379                      BufferUsage::FRONT_BUFFER,
380             .reservedSize = 0,
381     };
382     const bool supported = isSupported(info);
383     auto buffer = allocate(info);
384     if (!supported) {
385         ASSERT_EQ(nullptr, buffer.get())
386                 << "Allocation succeeded, but IMapper::isSupported was false";
387         GTEST_SKIP();
388     } else {
389         ASSERT_NE(nullptr, buffer.get()) << "Allocation failed, but IMapper::isSupported was true";
390     }
391 
392     AHardwareBuffer* ahb = buffer->createAHardwareBuffer();
393     ASSERT_NE(nullptr, ahb);
394 
395     // We draw 3 times with 3 different colors to ensure the flush is consistently flushing.
396     // Particularly for glFlush() there's occasions where it seems something triggers a flush
397     // to happen even though glFlush itself isn't consistently doing so, but for FRONT_BUFFER
398     // bound buffers it is supposed to consistently flush.
399     for (uint32_t color : {0xFF0000FFu, 0x00FF00FFu, 0x0000FFFFu}) {
400         fillWithGpu(ahb, color);
401         uint32_t* addr;
402         ASSERT_EQ(0, AHardwareBuffer_lock(ahb, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, -1, nullptr,
403                                           (void**)&addr));
404         // Spot check a few pixels
405         EXPECT_EQ(color, addr[0]);
406         EXPECT_EQ(color, addr[32 + (32 * buffer->stride())]);
407         AHardwareBuffer_unlock(ahb, nullptr);
408     }
409 
410     AHardwareBuffer_release(ahb);
411 }
412 
TEST_P(GraphicsFrontBufferTests,FrontBufferGpuToGpu)413 TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToGpu) {
414     BufferDescriptorInfo info{
415             .name = {"CPU_8888"},
416             .width = 64,
417             .height = 64,
418             .layerCount = 1,
419             .format = PixelFormat::RGBA_8888,
420             .usage = BufferUsage::GPU_RENDER_TARGET | BufferUsage::GPU_TEXTURE |
421                      BufferUsage::FRONT_BUFFER,
422             .reservedSize = 0,
423     };
424     const bool supported = isSupported(info);
425     auto buffer = allocate(info);
426     if (!supported) {
427         ASSERT_EQ(nullptr, buffer.get())
428                 << "Allocation succeeded, but IMapper::isSupported was false";
429         GTEST_SKIP();
430     } else {
431         ASSERT_NE(nullptr, buffer.get()) << "Allocation failed, but IMapper::isSupported was true";
432     }
433 
434     AHardwareBuffer* ahb = buffer->createAHardwareBuffer();
435     ASSERT_NE(nullptr, ahb);
436 
437     // We draw 3 times with 3 different colors to ensure the flush is consistently flushing.
438     // Particularly for glFlush() there's occasions where it seems something triggers a flush
439     // to happen even though glFlush itself isn't consistently doing so, but for FRONT_BUFFER
440     // bound buffers it is supposed to consistently flush.
441     for (uint32_t color : {0xFF0000FFu, 0x00FF00FFu, 0x0000FFFFu}) {
442         fillWithGpu(ahb, color);
443         sk_sp<Bitmap> hwBitmap = Bitmap::createFrom(ahb, SkColorSpace::MakeSRGB());
444         SkBitmap cpuBitmap = hwBitmap->getSkBitmap();
445         // Spot check a few pixels
446         EXPECT_EQ(color, *cpuBitmap.getAddr32(0, 0));
447         EXPECT_EQ(color, *cpuBitmap.getAddr32(16, 30));
448     }
449 
450     AHardwareBuffer_release(ahb);
451 }
452 
453 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsAllocatorAidlTests);
454 INSTANTIATE_TEST_CASE_P(PerInstance, GraphicsAllocatorAidlTests,
455                         testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
456                         PrintInstanceNameToString);
457 
458 const auto FlushMethodsValues = testing::Values(
__anonf04e1de90302(EglManager&) 459         FlushMethod{"glFinish", [](EglManager&) { glFinish(); }},
460         FlushMethod{"glFlush",
__anonf04e1de90402(EglManager&) 461                     [](EglManager&) {
462                         glFlush();
463                         // Since the goal is to verify that glFlush() actually flushes, we can't
464                         // wait on any sort of fence since that will change behavior So instead we
465                         // just sleep & hope
466                         sleep(1);
467                     }},
__anonf04e1de90502(EglManager& eglManager) 468         FlushMethod{"eglClientWaitSync", [](EglManager& eglManager) {
469                         EGLDisplay display = eglManager.eglDisplay();
470                         EGLSyncKHR fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
471                         eglClientWaitSyncKHR(display, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
472                                              EGL_FOREVER_KHR);
473                         eglDestroySyncKHR(display, fence);
474                     }});
475 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsFrontBufferTests);
476 INSTANTIATE_TEST_CASE_P(
477         PerInstance, GraphicsFrontBufferTests,
478         testing::Combine(testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
479                          FlushMethodsValues),
__anonf04e1de90602(auto info) 480         [](auto info) -> std::string {
481             std::string name = std::to_string(info.index) + "/" + std::get<1>(info.param).name;
482             return Sanitize(name);
483         });