• 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/hardware/graphics/mapper/4.0/IMapper.h>
29 #include <gtest/gtest.h>
30 #include <hidl/GtestPrinter.h>
31 #include <hidl/ServiceManagement.h>
32 #include <hwui/Bitmap.h>
33 #include <renderthread/EglManager.h>
34 #include <utils/GLUtils.h>
35 #include <vndk/hardware_buffer.h>
36 #include <initializer_list>
37 #include <optional>
38 #include <string>
39 #include <tuple>
40 
41 using namespace aidl::android::hardware::graphics::allocator;
42 using namespace aidl::android::hardware::graphics::common;
43 using namespace android;
44 using namespace android::hardware;
45 using namespace android::hardware::graphics::mapper::V4_0;
46 using android::uirenderer::AutoEglImage;
47 using android::uirenderer::AutoGLFramebuffer;
48 using android::uirenderer::AutoSkiaGlTexture;
49 using android::uirenderer::renderthread::EglManager;
50 
pack(const std::initializer_list<BufferUsage> & usages)51 static constexpr uint64_t pack(const std::initializer_list<BufferUsage>& usages) {
52     uint64_t ret = 0;
53     for (const auto u : usages) {
54         ret |= static_cast<uint64_t>(u);
55     }
56     return ret;
57 }
58 
cast(PixelFormat format)59 static constexpr hardware::graphics::common::V1_2::PixelFormat cast(PixelFormat format) {
60     return static_cast<hardware::graphics::common::V1_2::PixelFormat>(format);
61 }
62 
63 class BufferHandle {
64     sp<IMapper> mMapper;
65     native_handle_t* mRawHandle;
66     bool mImported = false;
67     uint32_t mStride;
68     const IMapper::BufferDescriptorInfo mInfo;
69 
70     BufferHandle(const BufferHandle&) = delete;
71     void operator=(const BufferHandle&) = delete;
72 
73   public:
BufferHandle(const sp<IMapper> mapper,native_handle_t * handle,bool imported,uint32_t stride,const IMapper::BufferDescriptorInfo & info)74     BufferHandle(const sp<IMapper> mapper, native_handle_t* handle, bool imported, uint32_t stride,
75                  const IMapper::BufferDescriptorInfo& info)
76         : mMapper(mapper), mRawHandle(handle), mImported(imported), mStride(stride), mInfo(info) {}
77 
~BufferHandle()78     ~BufferHandle() {
79         if (mRawHandle == nullptr) return;
80 
81         if (mImported) {
82             Error error = mMapper->freeBuffer(mRawHandle);
83             EXPECT_EQ(Error::NONE, error) << "failed to free buffer " << mRawHandle;
84         } else {
85             native_handle_close(mRawHandle);
86             native_handle_delete(mRawHandle);
87         }
88     }
89 
stride() const90     uint32_t stride() const { return mStride; }
91 
describe() const92     AHardwareBuffer_Desc describe() const {
93         return {
94                 .width = mInfo.width,
95                 .height = mInfo.height,
96                 .layers = mInfo.layerCount,
97                 .format = static_cast<uint32_t>(mInfo.format),
98                 .usage = mInfo.usage,
99                 .stride = stride(),
100                 .rfu0 = 0,
101                 .rfu1 = 0,
102         };
103     }
104 
createAHardwareBuffer() const105     AHardwareBuffer* createAHardwareBuffer() const {
106         auto desc = describe();
107         AHardwareBuffer* buffer = nullptr;
108         int err = AHardwareBuffer_createFromHandle(
109                 &desc, mRawHandle, AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, &buffer);
110         EXPECT_EQ(0, err) << "Failed to AHardwareBuffer_createFromHandle";
111         return err ? nullptr : buffer;
112     }
113 };
114 
115 class GraphicsTestsBase {
116   private:
117     std::shared_ptr<IAllocator> mAllocator;
118     sp<IMapper> mMapper;
119 
120   protected:
Initialize(std::string allocatorService,std::string mapperService)121     void Initialize(std::string allocatorService, std::string mapperService) {
122         mAllocator = IAllocator::fromBinder(
123                 ndk::SpAIBinder(AServiceManager_checkService(allocatorService.c_str())));
124         mMapper = IMapper::getService(mapperService);
125 
126         ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
127         ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
128         ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
129     }
130 
131   public:
createDescriptor(const IMapper::BufferDescriptorInfo & descriptorInfo)132     BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo) {
133         BufferDescriptor descriptor;
134         mMapper->createDescriptor(
135                 descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
136                     ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
137                     descriptor = tmpDescriptor;
138                 });
139 
140         return descriptor;
141     }
142 
allocate(const IMapper::BufferDescriptorInfo & descriptorInfo)143     std::unique_ptr<BufferHandle> allocate(const IMapper::BufferDescriptorInfo& descriptorInfo) {
144         auto descriptor = createDescriptor(descriptorInfo);
145         if (::testing::Test::HasFatalFailure()) {
146             return nullptr;
147         }
148 
149         AllocationResult result;
150         auto status = mAllocator->allocate(descriptor, 1, &result);
151         if (!status.isOk()) {
152             status_t error = status.getExceptionCode();
153             if (error == EX_SERVICE_SPECIFIC) {
154                 error = status.getServiceSpecificError();
155                 EXPECT_NE(OK, error) << "Failed to set error properly";
156             } else {
157                 EXPECT_EQ(OK, error) << "Allocation transport failure";
158             }
159             return nullptr;
160         } else {
161             return std::make_unique<BufferHandle>(mMapper, dupFromAidl(result.buffers[0]), false,
162                                                   result.stride, descriptorInfo);
163         }
164     }
165 
isSupported(const IMapper::BufferDescriptorInfo & descriptorInfo)166     bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo) {
167         bool ret = false;
168         EXPECT_TRUE(mMapper->isSupported(descriptorInfo,
169                                          [&](auto error, bool supported) {
170                                              ASSERT_EQ(Error::NONE, error);
171                                              ret = supported;
172                                          })
173                             .isOk());
174         return ret;
175     }
176 };
177 
178 class GraphicsAllocatorAidlTests
179     : public GraphicsTestsBase,
180       public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
181   public:
SetUp()182     void SetUp() override { Initialize(std::get<0>(GetParam()), std::get<1>(GetParam())); }
183 
TearDown()184     void TearDown() override {}
185 };
186 
187 struct FlushMethod {
188     std::string name;
189     std::function<void(EglManager&)> func;
190 };
191 
192 class GraphicsFrontBufferTests
193     : public GraphicsTestsBase,
194       public ::testing::TestWithParam<std::tuple<std::string, std::string, FlushMethod>> {
195   private:
196     EglManager eglManager;
197     std::function<void(EglManager&)> flush;
198 
199   public:
SetUp()200     void SetUp() override {
201         Initialize(std::get<0>(GetParam()), std::get<1>(GetParam()));
202         flush = std::get<2>(GetParam()).func;
203         eglManager.initialize();
204     }
205 
TearDown()206     void TearDown() override { eglManager.destroy(); }
207 
fillWithGpu(AHardwareBuffer * buffer,float red,float green,float blue,float alpha)208     void fillWithGpu(AHardwareBuffer* buffer, float red, float green, float blue, float alpha) {
209         const EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(buffer);
210         AutoEglImage eglImage(eglManager.eglDisplay(), clientBuffer);
211         AutoSkiaGlTexture glTexture;
212         AutoGLFramebuffer glFbo;
213         glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglImage.image);
214         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
215                                glTexture.mTexture, 0);
216 
217         AHardwareBuffer_Desc desc;
218         AHardwareBuffer_describe(buffer, &desc);
219         glViewport(0, 0, desc.width, desc.height);
220         glDisable(GL_STENCIL_TEST);
221         glDisable(GL_SCISSOR_TEST);
222         glClearColor(red, green, blue, alpha);
223         glClear(GL_COLOR_BUFFER_BIT);
224         flush(eglManager);
225     }
226 
fillWithGpu(AHardwareBuffer * buffer,uint32_t color)227     void fillWithGpu(AHardwareBuffer* buffer, /*RGBA*/ uint32_t color) {
228         // Keep it simple for now
229         static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__);
230         float a = float((color >> 24) & 0xff) / 255.0f;
231         float b = float((color >> 16) & 0xff) / 255.0f;
232         float g = float((color >> 8) & 0xff) / 255.0f;
233         float r = float((color)&0xff) / 255.0f;
234         fillWithGpu(buffer, r, g, b, a);
235     }
236 };
237 
TEST_P(GraphicsAllocatorAidlTests,CreateDescriptorBasic)238 TEST_P(GraphicsAllocatorAidlTests, CreateDescriptorBasic) {
239     ASSERT_NO_FATAL_FAILURE(createDescriptor({
240             .name = "CPU_8888",
241             .width = 64,
242             .height = 64,
243             .layerCount = 1,
244             .format = cast(PixelFormat::RGBA_8888),
245             .usage = pack({BufferUsage::CPU_WRITE_OFTEN, BufferUsage::CPU_READ_OFTEN}),
246             .reservedSize = 0,
247     }));
248 }
249 
TEST_P(GraphicsAllocatorAidlTests,CanAllocate)250 TEST_P(GraphicsAllocatorAidlTests, CanAllocate) {
251     auto buffer = allocate({
252             .name = "CPU_8888",
253             .width = 64,
254             .height = 64,
255             .layerCount = 1,
256             .format = cast(PixelFormat::RGBA_8888),
257             .usage = pack({BufferUsage::CPU_WRITE_OFTEN, BufferUsage::CPU_READ_OFTEN}),
258             .reservedSize = 0,
259     });
260     ASSERT_NE(nullptr, buffer.get());
261     EXPECT_GE(buffer->stride(), 64);
262 }
263 
TEST_P(GraphicsFrontBufferTests,FrontBufferGpuToCpu)264 TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToCpu) {
265     IMapper::BufferDescriptorInfo info{
266             .name = "CPU_8888",
267             .width = 64,
268             .height = 64,
269             .layerCount = 1,
270             .format = cast(PixelFormat::RGBA_8888),
271             .usage = pack({BufferUsage::GPU_RENDER_TARGET, BufferUsage::CPU_READ_OFTEN,
272                            BufferUsage::FRONT_BUFFER}),
273             .reservedSize = 0,
274     };
275     const bool supported = isSupported(info);
276     auto buffer = allocate(info);
277     if (!supported) {
278         ASSERT_EQ(nullptr, buffer.get())
279                 << "Allocation succeeded, but IMapper::isSupported was false";
280         GTEST_SKIP();
281     } else {
282         ASSERT_NE(nullptr, buffer.get()) << "Allocation failed, but IMapper::isSupported was true";
283     }
284 
285     AHardwareBuffer* ahb = buffer->createAHardwareBuffer();
286     ASSERT_NE(nullptr, ahb);
287 
288     // We draw 3 times with 3 different colors to ensure the flush is consistently flushing.
289     // Particularly for glFlush() there's occasions where it seems something triggers a flush
290     // to happen even though glFlush itself isn't consistently doing so, but for FRONT_BUFFER
291     // bound buffers it is supposed to consistently flush.
292     for (uint32_t color : {0xFF0000FFu, 0x00FF00FFu, 0x0000FFFFu}) {
293         fillWithGpu(ahb, color);
294         uint32_t* addr;
295         ASSERT_EQ(0, AHardwareBuffer_lock(ahb, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, -1, nullptr,
296                                           (void**)&addr));
297         // Spot check a few pixels
298         EXPECT_EQ(color, addr[0]);
299         EXPECT_EQ(color, addr[32 + (32 * buffer->stride())]);
300         AHardwareBuffer_unlock(ahb, nullptr);
301     }
302 
303     AHardwareBuffer_release(ahb);
304 }
305 
TEST_P(GraphicsFrontBufferTests,FrontBufferGpuToGpu)306 TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToGpu) {
307     IMapper::BufferDescriptorInfo info{
308             .name = "CPU_8888",
309             .width = 64,
310             .height = 64,
311             .layerCount = 1,
312             .format = cast(PixelFormat::RGBA_8888),
313             .usage = pack({BufferUsage::GPU_RENDER_TARGET, BufferUsage::GPU_TEXTURE,
314                            BufferUsage::FRONT_BUFFER}),
315             .reservedSize = 0,
316     };
317     const bool supported = isSupported(info);
318     auto buffer = allocate(info);
319     if (!supported) {
320         ASSERT_EQ(nullptr, buffer.get())
321                 << "Allocation succeeded, but IMapper::isSupported was false";
322         GTEST_SKIP();
323     } else {
324         ASSERT_NE(nullptr, buffer.get()) << "Allocation failed, but IMapper::isSupported was true";
325     }
326 
327     AHardwareBuffer* ahb = buffer->createAHardwareBuffer();
328     ASSERT_NE(nullptr, ahb);
329 
330     // We draw 3 times with 3 different colors to ensure the flush is consistently flushing.
331     // Particularly for glFlush() there's occasions where it seems something triggers a flush
332     // to happen even though glFlush itself isn't consistently doing so, but for FRONT_BUFFER
333     // bound buffers it is supposed to consistently flush.
334     for (uint32_t color : {0xFF0000FFu, 0x00FF00FFu, 0x0000FFFFu}) {
335         fillWithGpu(ahb, color);
336         sk_sp<Bitmap> hwBitmap = Bitmap::createFrom(ahb, SkColorSpace::MakeSRGB());
337         SkBitmap cpuBitmap = hwBitmap->getSkBitmap();
338         // Spot check a few pixels
339         EXPECT_EQ(color, *cpuBitmap.getAddr32(0, 0));
340         EXPECT_EQ(color, *cpuBitmap.getAddr32(16, 30));
341     }
342 
343     AHardwareBuffer_release(ahb);
344 }
345 
346 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsAllocatorAidlTests);
347 INSTANTIATE_TEST_CASE_P(
348         PerInstance, GraphicsAllocatorAidlTests,
349         testing::Combine(testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
350                          testing::ValuesIn(getAllHalInstanceNames(IMapper::descriptor))),
351         PrintInstanceTupleNameToString<>);
352 
353 const auto FlushMethodsValues = testing::Values(
__anonb00c18150302(EglManager&) 354         FlushMethod{"glFinish", [](EglManager&) { glFinish(); }},
355         FlushMethod{"glFlush",
__anonb00c18150402(EglManager&) 356                     [](EglManager&) {
357                         glFlush();
358                         // Since the goal is to verify that glFlush() actually flushes, we can't
359                         // wait on any sort of fence since that will change behavior So instead we
360                         // just sleep & hope
361                         sleep(1);
362                     }},
__anonb00c18150502(EglManager& eglManager) 363         FlushMethod{"eglClientWaitSync", [](EglManager& eglManager) {
364                         EGLDisplay display = eglManager.eglDisplay();
365                         EGLSyncKHR fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, NULL);
366                         eglClientWaitSyncKHR(display, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
367                                              EGL_FOREVER_KHR);
368                         eglDestroySyncKHR(display, fence);
369                     }});
370 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsFrontBufferTests);
371 INSTANTIATE_TEST_CASE_P(
372         PerInstance, GraphicsFrontBufferTests,
373         testing::Combine(testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
374                          testing::ValuesIn(getAllHalInstanceNames(IMapper::descriptor)),
375                          FlushMethodsValues),
__anonb00c18150602(auto info) 376         [](auto info) -> std::string {
377             std::string name = std::to_string(info.index) + "/" + std::get<2>(info.param).name;
378             return Sanitize(name);
379         });
380