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