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 });