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
17class DvrDisplayTest : public DvrApiTest {
18 protected:
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
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
69TEST_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
121TEST_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
189TEST_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
299void 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