Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7ea026c4 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "More dvr display test." into pi-dev

parents 99996d00 2cbf96ca
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -3,8 +3,6 @@

#include <gtest/gtest.h>

#define ASSERT_NOT_NULL(x) ASSERT_TRUE((x) != nullptr)

/** DvrTestBase loads the libdvr.so at runtime and get the Dvr API version 1. */
class DvrApiTest : public ::testing::Test {
 protected:
@@ -17,11 +15,11 @@ class DvrApiTest : public ::testing::Test {
    // https://github.com/android-ndk/ndk/issues/360
    flags |= RTLD_NODELETE;
    platform_handle_ = dlopen("libdvr.so", flags);
    ASSERT_NOT_NULL(platform_handle_) << "Dvr shared library missing.";
    ASSERT_NE(nullptr, platform_handle_) << "Dvr shared library missing.";

    auto dvr_get_api = reinterpret_cast<decltype(&dvrGetApi)>(
        dlsym(platform_handle_, "dvrGetApi"));
    ASSERT_NOT_NULL(dvr_get_api) << "Platform library missing dvrGetApi.";
    ASSERT_NE(nullptr, dvr_get_api) << "Platform library missing dvrGetApi.";

    ASSERT_EQ(dvr_get_api(&api_, sizeof(api_), /*version=*/1), 0)
        << "Unable to find compatible Dvr API.";
+277 −47
Original line number Diff line number Diff line
@@ -16,20 +16,58 @@

class DvrDisplayTest : public DvrApiTest {
 protected:
  void SetUp() override {
    DvrApiTest::SetUp();
    int ret = api_.GetNativeDisplayMetrics(sizeof(display_metrics_),
                                           &display_metrics_);
    ASSERT_EQ(ret, 0) << "Failed to get display metrics.";
    ALOGD(
        "display_width: %d, display_height: %d, display_x_dpi: %d, "
        "display_y_dpi: %d, vsync_period_ns: %d.",
        display_metrics_.display_width, display_metrics_.display_height,
        display_metrics_.display_x_dpi, display_metrics_.display_y_dpi,
        display_metrics_.vsync_period_ns);
  }

  void TearDown() override {
    if (write_queue_ != nullptr) {
      api_.WriteBufferQueueDestroy(write_queue_);
      write_queue_ = nullptr;
    }
    if (direct_surface_ != nullptr) {
      api_.SurfaceDestroy(direct_surface_);
      direct_surface_ = nullptr;
    }
    DvrApiTest::TearDown();
  }

  /* Convert a write buffer to an android hardware buffer and fill in
   * color_textures evenly to the buffer.
   * AssertionError if the width of the buffer is not equal to the input width,
   * AssertionError if the height of the buffer is not equal to the input
   * height.
   */
  void FillWriteBuffer(DvrWriteBuffer* write_buffer,
                       const std::vector<uint32_t>& color_textures,
                       uint32_t width, uint32_t height);

  // Write buffer queue properties.
  static constexpr uint64_t kUsage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
                                     AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
                                     AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
  uint32_t kFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
  static constexpr size_t kMetadataSize = 0;
  static constexpr int kTimeoutMs = 1000;  // Time for getting buffer.
  uint32_t kLayerCount = 1;
  DvrWriteBufferQueue* write_queue_ = nullptr;
  DvrSurface* direct_surface_ = nullptr;

  // Device display properties.
  DvrNativeDisplayMetrics display_metrics_;
};

TEST_F(DvrDisplayTest, DisplaySingleColor) {
  // Create direct surface.
  DvrSurface* direct_surface = nullptr;
TEST_F(DvrDisplayTest, DisplayWithOneBuffer) {
  // Create a direct surface.
  std::vector<DvrSurfaceAttribute> direct_surface_attributes = {
      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
@@ -43,79 +81,271 @@ TEST_F(DvrDisplayTest, DisplaySingleColor) {
  };
  int ret =
      api_.SurfaceCreate(direct_surface_attributes.data(),
                         direct_surface_attributes.size(), &direct_surface);
                         direct_surface_attributes.size(), &direct_surface_);
  ASSERT_EQ(ret, 0) << "Failed to create direct surface.";

  // Get screen dimension.
  DvrNativeDisplayMetrics display_metrics;
  ret = api_.GetNativeDisplayMetrics(sizeof(display_metrics), &display_metrics);
  ASSERT_EQ(ret, 0) << "Failed to get display metrics.";
  ALOGD(
      "display_width: %d, display_height: %d, display_x_dpi: %d, "
      "display_y_dpi: %d, vsync_period_ns: %d.",
      display_metrics.display_width, display_metrics.display_height,
      display_metrics.display_x_dpi, display_metrics.display_y_dpi,
      display_metrics.vsync_period_ns);

  // Create a buffer queue with the direct surface.
  constexpr uint32_t kLayerCount = 1;
  constexpr uint64_t kUsage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
                              AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
                              AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
  constexpr uint32_t kFormat = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
  constexpr size_t kCapacity = 1;
  constexpr size_t kMetadataSize = 0;
  uint32_t width = display_metrics.display_width;
  uint32_t height = display_metrics.display_height;
  uint32_t width = display_metrics_.display_width;
  uint32_t height = display_metrics_.display_height;
  ret = api_.SurfaceCreateWriteBufferQueue(
      direct_surface, width, height, kFormat, kLayerCount, kUsage, kCapacity,
      direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity,
      kMetadataSize, &write_queue_);
  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
  ASSERT_NOT_NULL(write_queue_) << "Write buffer queue should not be null.";
  ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null.";

  // Get buffer from WriteBufferQueue.
  DvrWriteBuffer* write_buffer = nullptr;
  constexpr int kTimeoutMs = 1000;
  DvrNativeBufferMetadata out_meta;
  int out_fence_fd = -1;
  ret = api_.WriteBufferQueueGainBuffer(write_queue_, kTimeoutMs, &write_buffer,
                                        &out_meta, &out_fence_fd);
  EXPECT_EQ(0, ret) << "Failed to get the buffer.";
  ASSERT_NOT_NULL(write_buffer) << "Gained buffer should not be null.";
  ASSERT_NE(nullptr, write_buffer) << "Gained buffer should not be null.";

  // Color the write buffer.
  FillWriteBuffer(write_buffer,
                  {0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
                  width, height);

  // Post buffer.
  int ready_fence_fd = -1;
  ret = api_.WriteBufferQueuePostBuffer(write_queue_, write_buffer, &out_meta,
                                        ready_fence_fd);
  EXPECT_EQ(0, ret) << "Failed to post the buffer.";

  sleep(5);  // For visual check on the device under test.
  // Should observe three primary colors on the screen center.
}

TEST_F(DvrDisplayTest, DisplayWithDoubleBuffering) {
  // Create a direct surface.
  std::vector<DvrSurfaceAttribute> direct_surface_attributes = {
      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
       .value.bool_value = true},
      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
       .value.int32_value = 10},
      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
       .value.bool_value = true},
  };
  int ret =
      api_.SurfaceCreate(direct_surface_attributes.data(),
                         direct_surface_attributes.size(), &direct_surface_);
  ASSERT_EQ(ret, 0) << "Failed to create direct surface.";

  // Convert to an android hardware buffer.
  AHardwareBuffer* ah_buffer{nullptr};
  ret = api_.WriteBufferGetAHardwareBuffer(write_buffer, &ah_buffer);
  EXPECT_EQ(0, ret) << "Failed to get a hardware buffer from the write buffer.";
  ASSERT_NOT_NULL(ah_buffer) << "AHardware buffer should not be null.";
  // Create a buffer queue with the direct surface.
  constexpr size_t kCapacity = 2;
  uint32_t width = display_metrics_.display_width;
  uint32_t height = display_metrics_.display_height;
  ret = api_.SurfaceCreateWriteBufferQueue(
      direct_surface_, width, height, kFormat, kLayerCount, kUsage, kCapacity,
      kMetadataSize, &write_queue_);
  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
  ASSERT_NE(nullptr, write_queue_) << "Write buffer queue should not be null.";

  int num_display_cycles_in_5s = 5 / (display_metrics_.vsync_period_ns / 1e9);
  ALOGD("The number of display cycles: %d", num_display_cycles_in_5s);
  int bufferhub_id_prev_write_buffer = -1;
  for (int i = 0; i < num_display_cycles_in_5s; ++i) {
    // Get a buffer from the WriteBufferQueue.
    DvrWriteBuffer* write_buffer = nullptr;
    DvrNativeBufferMetadata out_meta;
    int out_fence_fd = -1;
    ret = api_.WriteBufferQueueGainBuffer(
        write_queue_, kTimeoutMs, &write_buffer, &out_meta, &out_fence_fd);
    EXPECT_EQ(0, ret) << "Failed to get the a write buffer.";
    ASSERT_NE(nullptr, write_buffer) << "The gained buffer should not be null.";

    int bufferhub_id = api_.WriteBufferGetId(write_buffer);
    ALOGD("Display cycle: %d, bufferhub id of the write buffer: %d", i,
          bufferhub_id);
    EXPECT_NE(bufferhub_id_prev_write_buffer, bufferhub_id)
        << "Double buffering should be using the two buffers in turns, not "
           "reusing the same write buffer.";
    bufferhub_id_prev_write_buffer = bufferhub_id;

    // Color the write buffer.
    if (i % 2) {
      FillWriteBuffer(write_buffer, {0xffff0000, 0xff00ff00, 0xff0000ff}, width,
                      height);
    } else {
      FillWriteBuffer(write_buffer, {0xff00ff00, 0xff0000ff, 0xffff0000}, width,
                      height);
    }

    // Post the write buffer.
    int ready_fence_fd = -1;
    ret = api_.WriteBufferQueuePostBuffer(write_queue_, write_buffer, &out_meta,
                                          ready_fence_fd);
    EXPECT_EQ(0, ret) << "Failed to post the buffer.";
  }
  // Should observe blinking screen in secondary colors
  // although it is actually displaying primary colors.
}

TEST_F(DvrDisplayTest, DisplayWithTwoHardwareLayers) {
  // Create the direct_surface_0 of z order 10 and direct_surface_1 of z
  // order 11.
  DvrSurface* direct_surface_0 = nullptr;
  std::vector<DvrSurfaceAttribute> direct_surface_0_attributes = {
      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
       .value.bool_value = true},
      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
       .value.int32_value = 10},
      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
       .value.bool_value = true},
  };
  int ret =
      api_.SurfaceCreate(direct_surface_0_attributes.data(),
                         direct_surface_0_attributes.size(), &direct_surface_0);
  EXPECT_EQ(ret, 0) << "Failed to create direct surface.";

  DvrSurface* direct_surface_1 = nullptr;
  std::vector<DvrSurfaceAttribute> direct_surface_1_attributes = {
      {.key = DVR_SURFACE_ATTRIBUTE_DIRECT,
       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
       .value.bool_value = true},
      {.key = DVR_SURFACE_ATTRIBUTE_Z_ORDER,
       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
       .value.int32_value = 11},
      {.key = DVR_SURFACE_ATTRIBUTE_VISIBLE,
       .value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
       .value.bool_value = true},
  };
  ret =
      api_.SurfaceCreate(direct_surface_1_attributes.data(),
                         direct_surface_1_attributes.size(), &direct_surface_1);
  EXPECT_EQ(ret, 0) << "Failed to create direct surface.";

  // Create a buffer queue for each of the direct surfaces.
  constexpr size_t kCapacity = 1;
  uint32_t width = display_metrics_.display_width;
  uint32_t height = display_metrics_.display_height;

  DvrWriteBufferQueue* write_queue_0 = nullptr;
  ret = api_.SurfaceCreateWriteBufferQueue(
      direct_surface_0, width, height, kFormat, kLayerCount, kUsage, kCapacity,
      kMetadataSize, &write_queue_0);
  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
  EXPECT_NE(nullptr, write_queue_0) << "Write buffer queue should not be null.";

  DvrWriteBufferQueue* write_queue_1 = nullptr;
  ret = api_.SurfaceCreateWriteBufferQueue(
      direct_surface_1, width, height, kFormat, kLayerCount, kUsage, kCapacity,
      kMetadataSize, &write_queue_1);
  EXPECT_EQ(0, ret) << "Failed to create buffer queue.";
  EXPECT_NE(nullptr, write_queue_1) << "Write buffer queue should not be null.";

  // Get a buffer from each of the write buffer queues.
  DvrWriteBuffer* write_buffer_0 = nullptr;
  DvrNativeBufferMetadata out_meta_0;
  int out_fence_fd = -1;
  ret = api_.WriteBufferQueueGainBuffer(
      write_queue_0, kTimeoutMs, &write_buffer_0, &out_meta_0, &out_fence_fd);
  EXPECT_EQ(0, ret) << "Failed to get the buffer.";
  EXPECT_NE(nullptr, write_buffer_0) << "Gained buffer should not be null.";

  DvrWriteBuffer* write_buffer_1 = nullptr;
  DvrNativeBufferMetadata out_meta_1;
  out_fence_fd = -1;
  ret = api_.WriteBufferQueueGainBuffer(
      write_queue_1, kTimeoutMs, &write_buffer_1, &out_meta_1, &out_fence_fd);
  EXPECT_EQ(0, ret) << "Failed to get the buffer.";
  EXPECT_NE(nullptr, write_buffer_1) << "Gained buffer should not be null.";

  // Color the write buffers.
  FillWriteBuffer(write_buffer_0, {0xffff0000, 0xff00ff00, 0xff0000ff}, width,
                  height);
  FillWriteBuffer(write_buffer_1, {0x7f00ff00, 0x7f0000ff, 0x7fff0000}, width,
                  height);

  // Post buffers.
  int ready_fence_fd = -1;
  ret = api_.WriteBufferQueuePostBuffer(write_queue_0, write_buffer_0,
                                        &out_meta_0, ready_fence_fd);
  EXPECT_EQ(0, ret) << "Failed to post the buffer.";

  ready_fence_fd = -1;
  ret = api_.WriteBufferQueuePostBuffer(write_queue_1, write_buffer_1,
                                        &out_meta_1, ready_fence_fd);
  EXPECT_EQ(0, ret) << "Failed to post the buffer.";

  sleep(5);  // For visual check on the device under test.
  // Should observe three secondary colors.

  // Test finished. Clean up buffers and surfaces.
  if (write_queue_0 != nullptr) {
    api_.WriteBufferQueueDestroy(write_queue_0);
    write_queue_0 = nullptr;
  }
  if (write_queue_1 != nullptr) {
    api_.WriteBufferQueueDestroy(write_queue_1);
    write_queue_1 = nullptr;
  }
  if (direct_surface_0 != nullptr) {
    api_.SurfaceDestroy(direct_surface_0);
  }
  if (direct_surface_1 != nullptr) {
    api_.SurfaceDestroy(direct_surface_1);
  }
}

void DvrDisplayTest::FillWriteBuffer(
    DvrWriteBuffer* write_buffer, const std::vector<uint32_t>& color_textures,
    uint32_t width, uint32_t height) {
  uint32_t num_colors = color_textures.size();
  // Convert the first write buffer to an android hardware buffer.
  AHardwareBuffer* ah_buffer = nullptr;
  int ret = api_.WriteBufferGetAHardwareBuffer(write_buffer, &ah_buffer);
  ASSERT_EQ(0, ret) << "Failed to get a hardware buffer from the write buffer.";
  ASSERT_NE(nullptr, ah_buffer) << "AHardware buffer should not be null.";
  AHardwareBuffer_Desc ah_buffer_describe;
  AHardwareBuffer_describe(ah_buffer, &ah_buffer_describe);
  ASSERT_EQ(ah_buffer_describe.format, kFormat)
      << "The format of the android hardware buffer is wrong.";
  ASSERT_EQ(ah_buffer_describe.layers, kLayerCount)
      << "The obtained android hardware buffer should have 2 layers.";
  ASSERT_EQ(ah_buffer_describe.width, width)
      << "The obtained android hardware buffer width is wrong.";
  ASSERT_EQ(ah_buffer_describe.height, height)
      << "The obtained android hardware buffer height is wrong.";
  // Change the content of the android hardware buffer.
  void* buffer_data{nullptr};
  void* buffer_data = nullptr;
  int32_t fence = -1;
  ret = AHardwareBuffer_lock(ah_buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
                             fence, nullptr, &buffer_data);
  EXPECT_EQ(0, ret) << "Failed to lock the hardware buffer.";
  ASSERT_NOT_NULL(buffer_data) << "Buffer data should not be null.";
  ASSERT_EQ(0, ret) << "Failed to lock the hardware buffer.";
  ASSERT_NE(nullptr, buffer_data) << "Buffer data should not be null.";

  uint32_t color_texture = 0xff0000ff;  // Red color in RGBA.
  for (uint32_t i = 0; i < width * height; ++i) {
  uint32_t num_pixels = width * height / num_colors;
  for (uint32_t color_index = 0; color_index < num_colors - 1; ++color_index) {
    uint32_t color_texture = color_textures[color_index];
    for (uint32_t i = 0; i < num_pixels; ++i) {
      memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
                                   i * sizeof(color_texture)),
                                     (i + num_pixels * color_index) *
                                         sizeof(color_texture)),
             &color_texture, sizeof(color_texture));
    }
  }
  uint32_t color_texture = color_textures[num_colors - 1];
  uint32_t num_colored_pixels = num_pixels * (num_colors - 1);
  num_pixels = width * height - num_colored_pixels;
  for (uint32_t i = 0; i < num_pixels; ++i) {
    memcpy(reinterpret_cast<void*>(reinterpret_cast<int64_t>(buffer_data) +
                                   (i + num_colored_pixels) *
                                       sizeof(color_texture)),
           &color_texture, sizeof(color_texture));
  }

  fence = -1;
  ret = AHardwareBuffer_unlock(ah_buffer, &fence);
  EXPECT_EQ(0, ret) << "Failed to unlock the hardware buffer.";

  // Release the android hardware buffer.
  AHardwareBuffer_release(ah_buffer);

  // Post buffer.
  int ready_fence_fd = -1;
  ret = api_.WriteBufferQueuePostBuffer(write_queue_, write_buffer, &out_meta,
                                        ready_fence_fd);
  EXPECT_EQ(0, ret) << "Failed to post the buffer.";

  sleep(5);  // For visual check on the device under test.
}