1 #include <android/hardware_buffer.h>
2 #include <android/log.h>
3 #include <dvr/dvr_api.h>
4 #include <dvr/dvr_display_types.h>
5 #include <dvr/dvr_surface.h>
6 
7 #include <gtest/gtest.h>
8 
9 #include "dvr_api_test.h"
10 
11 #define LOG_TAG "dvr_display-test"
12 
13 #ifndef ALOGD
14 #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
15 #endif
16 
17 class DvrDisplayTest : public DvrApiTest {
18  protected:
SetUp()19   void SetUp() override {
20     DvrApiTest::SetUp();
21     int ret = api_.GetNativeDisplayMetrics(sizeof(display_metrics_),
22                                            &display_metrics_);
23     ASSERT_EQ(ret, 0) << "Failed to get display metrics.";
24     ALOGD(
25         "display_width: %d, display_height: %d, display_x_dpi: %d, "
26         "display_y_dpi: %d, vsync_period_ns: %d.",
27         display_metrics_.display_width, display_metrics_.display_height,
28         display_metrics_.display_x_dpi, display_metrics_.display_y_dpi,
29         display_metrics_.vsync_period_ns);
30   }
31 
TearDown()32   void TearDown() override {
33     if (write_queue_ != nullptr) {
34       api_.WriteBufferQueueDestroy(write_queue_);
35       write_queue_ = nullptr;
36     }
37     if (direct_surface_ != nullptr) {
38       api_.SurfaceDestroy(direct_surface_);
39       direct_surface_ = nullptr;
40     }
41     DvrApiTest::TearDown();
42   }
43 
44   /* Convert a write buffer to an android hardware buffer and fill in
45    * color_textures evenly to the buffer.
46    * AssertionError if the width of the buffer is not equal to the input width,
47    * AssertionError if the height of the buffer is not equal to the input
48    * height.
49    */
50   void FillWriteBuffer(DvrWriteBuffer* write_buffer,
51                        const std::vector<uint32_t>& color_textures,
52                        uint32_t width, uint32_t height);
53 
54   // Write buffer queue properties.
55   static constexpr uint64_t kUsage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
56                                      AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
57                                      AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
58   uint32_t kFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
59   static constexpr size_t kMetadataSize = 0;
60   static constexpr int kTimeoutMs = 1000;  // Time for getting buffer.
61   uint32_t kLayerCount = 1;
62   DvrWriteBufferQueue* write_queue_ = nullptr;
63   DvrSurface* direct_surface_ = nullptr;
64 
65   // Device display properties.
66   DvrNativeDisplayMetrics display_metrics_;
67 };
68 
TEST_F(DvrDisplayTest,DisplayWithOneBuffer)69 TEST_F(DvrDisplayTest, DisplayWithOneBuffer) {
70   // Create a direct surface.
71   std::vector<DvrSurfaceAttribute> direct_surface_attributes = {
72       {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
73        .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
74        .value.bool_value = true},
75       {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
76        .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
77        .value.int32_value = 10},
78       {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
79        .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
80        .value.bool_value = true},
81   };
82   int ret =
83       api_.SurfaceCreate(direct_surface_attributes.data(),
84                          direct_surface_attributes.size(), &direct_surface_);
85   ASSERT_EQ(ret, 0) << "Failed to create direct surface.";
86 
87   // Create a buffer queue with the direct surface.
88   constexpr size_t kCapacity = 1;
89   uint32_t width = display_metrics_.display_width;
90   uint32_t height = display_metrics_.display_height;
91   ret = api_.SurfaceCreateWriteBufferQueue(
92       direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity,
93       kMetadataSize, &write_queue_);
94   EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
95   ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null.";
96 
97   // Get buffer from WriteBufferQueue.
98   DvrWriteBuffer* write_buffer = nullptr;
99   DvrNativeBufferMetadata out_meta;
100   int out_fence_fd = -1;
101   ret = api_.WriteBufferQueueGainBuffer(write_queue_, kTimeoutMs, &write_buffer,
102                                         &out_meta, &out_fence_fd);
103   EXPECT_EQ(0, ret) << "Failed to get the buffer.";
104   ASSERT_NE(nullptr, write_buffer) << "Gained buffer should not be null.";
105 
106   // Color the write buffer.
107   FillWriteBuffer(write_buffer,
108                   {0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
109                   width, height);
110 
111   // Post buffer.
112   int ready_fence_fd = -1;
113   ret = api_.WriteBufferQueuePostBuffer(write_queue_, write_buffer, &out_meta,
114                                         ready_fence_fd);
115   EXPECT_EQ(0, ret) << "Failed to post the buffer.";
116 
117   sleep(5);  // For visual check on the device under test.
118   // Should observe three primary colors on the screen center.
119 }
120 
TEST_F(DvrDisplayTest,DisplayWithDoubleBuffering)121 TEST_F(DvrDisplayTest, DisplayWithDoubleBuffering) {
122   // Create a direct surface.
123   std::vector<DvrSurfaceAttribute> direct_surface_attributes = {
124       {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
125        .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
126        .value.bool_value = true},
127       {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
128        .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
129        .value.int32_value = 10},
130       {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
131        .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
132        .value.bool_value = true},
133   };
134   int ret =
135       api_.SurfaceCreate(direct_surface_attributes.data(),
136                          direct_surface_attributes.size(), &direct_surface_);
137   ASSERT_EQ(ret, 0) << "Failed to create direct surface.";
138 
139   // Create a buffer queue with the direct surface.
140   constexpr size_t kCapacity = 2;
141   uint32_t width = display_metrics_.display_width;
142   uint32_t height = display_metrics_.display_height;
143   ret = api_.SurfaceCreateWriteBufferQueue(
144       direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity,
145       kMetadataSize, &write_queue_);
146   EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
147   ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null.";
148 
149   int num_display_cycles_in_5s = 5 / (display_metrics_.vsync_period_ns / 1e9);
150   ALOGD("The number of display cycles: %d", num_display_cycles_in_5s);
151   int bufferhub_id_prev_write_buffer = -1;
152   for (int i = 0; i < num_display_cycles_in_5s; ++i) {
153     // Get a buffer from the WriteBufferQueue.
154     DvrWriteBuffer* write_buffer = nullptr;
155     DvrNativeBufferMetadata out_meta;
156     int out_fence_fd = -1;
157     ret = api_.WriteBufferQueueGainBuffer(
158         write_queue_, kTimeoutMs, &write_buffer, &out_meta, &out_fence_fd);
159     EXPECT_EQ(0, ret) << "Failed to get the a write buffer.";
160     ASSERT_NE(nullptr, write_buffer) << "The gained buffer should not be null.";
161 
162     int bufferhub_id = api_.WriteBufferGetId(write_buffer);
163     ALOGD("Display cycle: %d, bufferhub id of the write buffer: %d", i,
164           bufferhub_id);
165     EXPECT_NE(bufferhub_id_prev_write_buffer, bufferhub_id)
166         << "Double buffering should be using the two buffers in turns, not "
167            "reusing the same write buffer.";
168     bufferhub_id_prev_write_buffer = bufferhub_id;
169 
170     // Color the write buffer.
171     if (i % 2) {
172       FillWriteBuffer(write_buffer, {0xffff0000, 0xff00ff00, 0xff0000ff}, width,
173                       height);
174     } else {
175       FillWriteBuffer(write_buffer, {0xff00ff00, 0xff0000ff, 0xffff0000}, width,
176                       height);
177     }
178 
179     // Post the write buffer.
180     int ready_fence_fd = -1;
181     ret = api_.WriteBufferQueuePostBuffer(write_queue_, write_buffer, &out_meta,
182                                           ready_fence_fd);
183     EXPECT_EQ(0, ret) << "Failed to post the buffer.";
184   }
185   // Should observe blinking screen in secondary colors
186   // although it is actually displaying primary colors.
187 }
188 
TEST_F(DvrDisplayTest,DisplayWithTwoHardwareLayers)189 TEST_F(DvrDisplayTest, DisplayWithTwoHardwareLayers) {
190   // Create the direct_surface_0 of z order 10 and direct_surface_1 of z
191   // order 11.
192   DvrSurface* direct_surface_0 = nullptr;
193   std::vector<DvrSurfaceAttribute> direct_surface_0_attributes = {
194       {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
195        .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
196        .value.bool_value = true},
197       {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
198        .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
199        .value.int32_value = 10},
200       {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
201        .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
202        .value.bool_value = true},
203   };
204   int ret =
205       api_.SurfaceCreate(direct_surface_0_attributes.data(),
206                          direct_surface_0_attributes.size(), &direct_surface_0);
207   EXPECT_EQ(ret, 0) << "Failed to create direct surface.";
208 
209   DvrSurface* direct_surface_1 = nullptr;
210   std::vector<DvrSurfaceAttribute> direct_surface_1_attributes = {
211       {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
212        .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
213        .value.bool_value = true},
214       {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
215        .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
216        .value.int32_value = 11},
217       {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
218        .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
219        .value.bool_value = true},
220   };
221   ret =
222       api_.SurfaceCreate(direct_surface_1_attributes.data(),
223                          direct_surface_1_attributes.size(), &direct_surface_1);
224   EXPECT_EQ(ret, 0) << "Failed to create direct surface.";
225 
226   // Create a buffer queue for each of the direct surfaces.
227   constexpr size_t kCapacity = 1;
228   uint32_t width = display_metrics_.display_width;
229   uint32_t height = display_metrics_.display_height;
230 
231   DvrWriteBufferQueue* write_queue_0 = nullptr;
232   ret = api_.SurfaceCreateWriteBufferQueue(
233       direct_surface_0, width, height, kFormat, kLayerCount, kUsage, kCapacity,
234       kMetadataSize, &write_queue_0);
235   EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
236   EXPECT_NE(nullptr, write_queue_0) << "Write buffer queue should not be null.";
237 
238   DvrWriteBufferQueue* write_queue_1 = nullptr;
239   ret = api_.SurfaceCreateWriteBufferQueue(
240       direct_surface_1, width, height, kFormat, kLayerCount, kUsage, kCapacity,
241       kMetadataSize, &write_queue_1);
242   EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
243   EXPECT_NE(nullptr, write_queue_1) << "Write buffer queue should not be null.";
244 
245   // Get a buffer from each of the write buffer queues.
246   DvrWriteBuffer* write_buffer_0 = nullptr;
247   DvrNativeBufferMetadata out_meta_0;
248   int out_fence_fd = -1;
249   ret = api_.WriteBufferQueueGainBuffer(
250       write_queue_0, kTimeoutMs, &write_buffer_0, &out_meta_0, &out_fence_fd);
251   EXPECT_EQ(0, ret) << "Failed to get the buffer.";
252   EXPECT_NE(nullptr, write_buffer_0) << "Gained buffer should not be null.";
253 
254   DvrWriteBuffer* write_buffer_1 = nullptr;
255   DvrNativeBufferMetadata out_meta_1;
256   out_fence_fd = -1;
257   ret = api_.WriteBufferQueueGainBuffer(
258       write_queue_1, kTimeoutMs, &write_buffer_1, &out_meta_1, &out_fence_fd);
259   EXPECT_EQ(0, ret) << "Failed to get the buffer.";
260   EXPECT_NE(nullptr, write_buffer_1) << "Gained buffer should not be null.";
261 
262   // Color the write buffers.
263   FillWriteBuffer(write_buffer_0, {0xffff0000, 0xff00ff00, 0xff0000ff}, width,
264                   height);
265   FillWriteBuffer(write_buffer_1, {0x7f00ff00, 0x7f0000ff, 0x7fff0000}, width,
266                   height);
267 
268   // Post buffers.
269   int ready_fence_fd = -1;
270   ret = api_.WriteBufferQueuePostBuffer(write_queue_0, write_buffer_0,
271                                         &out_meta_0, ready_fence_fd);
272   EXPECT_EQ(0, ret) << "Failed to post the buffer.";
273 
274   ready_fence_fd = -1;
275   ret = api_.WriteBufferQueuePostBuffer(write_queue_1, write_buffer_1,
276                                         &out_meta_1, ready_fence_fd);
277   EXPECT_EQ(0, ret) << "Failed to post the buffer.";
278 
279   sleep(5);  // For visual check on the device under test.
280   // Should observe three secondary colors.
281 
282   // Test finished. Clean up buffers and surfaces.
283   if (write_queue_0 != nullptr) {
284     api_.WriteBufferQueueDestroy(write_queue_0);
285     write_queue_0 = nullptr;
286   }
287   if (write_queue_1 != nullptr) {
288     api_.WriteBufferQueueDestroy(write_queue_1);
289     write_queue_1 = nullptr;
290   }
291   if (direct_surface_0 != nullptr) {
292     api_.SurfaceDestroy(direct_surface_0);
293   }
294   if (direct_surface_1 != nullptr) {
295     api_.SurfaceDestroy(direct_surface_1);
296   }
297 }
298 
FillWriteBuffer(DvrWriteBuffer * write_buffer,const std::vector<uint32_t> & color_textures,uint32_t width,uint32_t height)299 void DvrDisplayTest::FillWriteBuffer(
300     DvrWriteBuffer* write_buffer, const std::vector<uint32_t>& color_textures,
301     uint32_t width, uint32_t height) {
302   uint32_t num_colors = color_textures.size();
303   // Convert the first write buffer to an android hardware buffer.
304   AHardwareBuffer* ah_buffer = nullptr;
305   int ret = api_.WriteBufferGetAHardwareBuffer(write_buffer, &ah_buffer);
306   ASSERT_EQ(0, ret) << "Failed to get a hardware buffer from the write buffer.";
307   ASSERT_NE(nullptr, ah_buffer) << "AHardware buffer should not be null.";
308   AHardwareBuffer_Desc ah_buffer_describe;
309   AHardwareBuffer_describe(ah_buffer, &ah_buffer_describe);
310   ASSERT_EQ(ah_buffer_describe.format, kFormat)
311       << "The format of the android hardware buffer is wrong.";
312   ASSERT_EQ(ah_buffer_describe.layers, kLayerCount)
313       << "The obtained android hardware buffer should have 2 layers.";
314   ASSERT_EQ(ah_buffer_describe.width, width)
315       << "The obtained android hardware buffer width is wrong.";
316   ASSERT_EQ(ah_buffer_describe.height, height)
317       << "The obtained android hardware buffer height is wrong.";
318   // Change the content of the android hardware buffer.
319   void* buffer_data = nullptr;
320   int32_t fence = -1;
321   ret = AHardwareBuffer_lock(ah_buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
322                              fence, nullptr, &buffer_data);
323   ASSERT_EQ(0, ret) << "Failed to lock the hardware buffer.";
324   ASSERT_NE(nullptr, buffer_data) << "Buffer data should not be null.";
325 
326   uint32_t num_pixels = width * height / num_colors;
327   for (uint32_t color_index = 0; color_index < num_colors - 1; ++color_index) {
328     uint32_t color_texture = color_textures[color_index];
329     for (uint32_t i = 0; i < num_pixels; ++i) {
330       memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
331                                      (i + num_pixels * color_index) *
332                                          sizeof(color_texture)),
333              &color_texture, sizeof(color_texture));
334     }
335   }
336   uint32_t color_texture = color_textures[num_colors - 1];
337   uint32_t num_colored_pixels = num_pixels * (num_colors - 1);
338   num_pixels = width * height - num_colored_pixels;
339   for (uint32_t i = 0; i < num_pixels; ++i) {
340     memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
341                                    (i + num_colored_pixels) *
342                                        sizeof(color_texture)),
343            &color_texture, sizeof(color_texture));
344   }
345   fence = -1;
346   ret = AHardwareBuffer_unlock(ah_buffer, &fence);
347   EXPECT_EQ(0, ret) << "Failed to unlock the hardware buffer.";
348 
349   // Release the android hardware buffer.
350   AHardwareBuffer_release(ah_buffer);
351 }
352