#include #include #include #include #include #include #include "dvr_api_test.h" #define LOG_TAG "dvr_display-test" #ifndef ALOGD #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #endif 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& 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, DisplayWithOneBuffer) { // Create a direct surface. std::vector 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."; // Create a buffer queue with the direct surface. constexpr size_t kCapacity = 1; 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."; // Get buffer from 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 buffer."; 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 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."; // 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 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 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& 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; int32_t fence = -1; ret = AHardwareBuffer_lock(ah_buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, fence, nullptr, &buffer_data); ASSERT_EQ(0, ret) << "Failed to lock the hardware buffer."; ASSERT_NE(nullptr, buffer_data) << "Buffer data should not be null."; 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(reinterpret_cast(buffer_data) + (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(reinterpret_cast(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); }