Loading libs/vr/libdisplay/display_client.cpp +10 −3 Original line number Original line Diff line number Diff line Loading @@ -104,9 +104,16 @@ Status<void> Surface::SetAttributes(const SurfaceAttributes& attributes) { return {}; return {}; } } Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue() { Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue(uint32_t width, uint32_t height, uint32_t format) { ALOGD_IF(TRACE, "Surface::CreateQueue: Creating empty queue."); ALOGD_IF(TRACE, "Surface::CreateQueue: Creating empty queue."); auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>(0); auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>( ProducerQueueConfigBuilder() .SetDefaultWidth(width) .SetDefaultHeight(height) .SetDefaultFormat(format) .Build()); if (!status) { if (!status) { ALOGE("Surface::CreateQueue: Failed to create queue: %s", ALOGE("Surface::CreateQueue: Failed to create queue: %s", status.GetErrorMessage().c_str()); status.GetErrorMessage().c_str()); Loading @@ -129,7 +136,7 @@ Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue( "Surface::CreateQueue: width=%u height=%u layer_count=%u format=%u " "Surface::CreateQueue: width=%u height=%u layer_count=%u format=%u " "usage=%" PRIx64 " capacity=%zu", "usage=%" PRIx64 " capacity=%zu", width, height, layer_count, format, usage, capacity); width, height, layer_count, format, usage, capacity); auto status = CreateQueue(); auto status = CreateQueue(width, height, format); if (!status) if (!status) return status.error_status(); return status.error_status(); Loading libs/vr/libdisplay/include/private/dvr/display_client.h +3 −1 Original line number Original line Diff line number Diff line Loading @@ -37,7 +37,9 @@ class Surface : public pdx::ClientBase<Surface> { pdx::Status<void> SetAttributes(const SurfaceAttributes& attributes); pdx::Status<void> SetAttributes(const SurfaceAttributes& attributes); // Creates an empty queue. // Creates an empty queue. pdx::Status<std::unique_ptr<ProducerQueue>> CreateQueue(); pdx::Status<std::unique_ptr<ProducerQueue>> CreateQueue(uint32_t width, uint32_t height, uint32_t format); // Creates a queue and populates it with |capacity| buffers of the specified // Creates a queue and populates it with |capacity| buffers of the specified // parameters. // parameters. Loading libs/vr/libdisplay/include/private/dvr/display_protocol.h +3 −2 Original line number Original line Diff line number Diff line Loading @@ -222,8 +222,9 @@ struct DisplayProtocol { PDX_REMOTE_METHOD(CreateSurface, kOpCreateSurface, PDX_REMOTE_METHOD(CreateSurface, kOpCreateSurface, SurfaceInfo(const SurfaceAttributes& attributes)); SurfaceInfo(const SurfaceAttributes& attributes)); PDX_REMOTE_METHOD(GetSurfaceInfo, kOpGetSurfaceInfo, SurfaceInfo(Void)); PDX_REMOTE_METHOD(GetSurfaceInfo, kOpGetSurfaceInfo, SurfaceInfo(Void)); PDX_REMOTE_METHOD(CreateQueue, kOpCreateQueue, PDX_REMOTE_METHOD( LocalChannelHandle(size_t meta_size_bytes)); CreateQueue, kOpCreateQueue, LocalChannelHandle(const ProducerQueueConfig& producer_config)); PDX_REMOTE_METHOD(SetAttributes, kOpSetAttributes, PDX_REMOTE_METHOD(SetAttributes, kOpSetAttributes, void(const SurfaceAttributes& attributes)); void(const SurfaceAttributes& attributes)); }; }; Loading libs/vr/libdvr/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,7 @@ cc_library_headers { cflags = [ cflags = [ "-DLOG_TAG=\"libdvr\"", "-DLOG_TAG=\"libdvr\"", "-DTRACE=0", ] ] srcs = [ srcs = [ Loading libs/vr/libdvr/dvr_buffer_queue.cpp +195 −108 Original line number Original line Diff line number Diff line Loading @@ -2,60 +2,174 @@ #include "include/dvr/dvr_buffer_queue.h" #include "include/dvr/dvr_buffer_queue.h" #include <android/native_window.h> #include <android/native_window.h> #include <gui/Surface.h> #include <private/dvr/buffer_hub_queue_client.h> #include <private/dvr/buffer_hub_queue_producer.h> #include <private/dvr/buffer_hub_queue_producer.h> #include "dvr_internal.h" #include "dvr_internal.h" #include "dvr_buffer_queue_internal.h" #define CHECK_PARAM(param) \ LOG_ALWAYS_FATAL_IF(param == nullptr, "%s: " #param "cannot be NULL.", \ __FUNCTION__) using namespace android; using namespace android; using android::dvr::BufferHubQueueProducer; using android::dvr::BufferProducer; using android::dvr::ConsumerQueue; using android::dvr::ProducerQueue; extern "C" { namespace android { DvrWriteBufferQueue::DvrWriteBufferQueue( namespace dvr { const std::shared_ptr<ProducerQueue>& producer_queue) : producer_queue_(producer_queue), width_(producer_queue->default_width()), height_(producer_queue->default_height()), format_(producer_queue->default_format()) {} DvrWriteBufferQueue* CreateDvrWriteBufferQueueFromProducerQueue( int DvrWriteBufferQueue::GetNativeWindow(ANativeWindow** out_window) { const std::shared_ptr<dvr::ProducerQueue>& producer_queue) { if (producer_queue_->metadata_size() != sizeof(DvrNativeBufferMetadata)) { return new DvrWriteBufferQueue{std::move(producer_queue)}; ALOGE( "DvrWriteBufferQueue::GetNativeWindow: The size of buffer metadata " "(%zu) of the write queue does not match of size of " "DvrNativeBufferMetadata (%zu).", producer_queue_->metadata_size(), sizeof(DvrNativeBufferMetadata)); return -EINVAL; } } DvrReadBufferQueue* CreateDvrReadBufferQueueFromConsumerQueue( if (native_window_ == nullptr) { const std::shared_ptr<dvr::ConsumerQueue>& consumer_queue) { // Lazy creation of |native_window|, as not everyone is using return new DvrReadBufferQueue{std::move(consumer_queue)}; // DvrWriteBufferQueue as an external surface. sp<IGraphicBufferProducer> gbp = BufferHubQueueProducer::Create(producer_queue_); native_window_ = new Surface(gbp, true); } } dvr::ProducerQueue* GetProducerQueueFromDvrWriteBufferQueue( *out_window = static_cast<ANativeWindow*>(native_window_.get()); DvrWriteBufferQueue* write_queue) { return 0; return write_queue->producer_queue.get(); } } } // namespace dvr int DvrWriteBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) { } // namespace android std::unique_ptr<ConsumerQueue> consumer_queue = producer_queue_->CreateConsumerQueue(); if (consumer_queue == nullptr) { ALOGE( "DvrWriteBufferQueue::CreateReadQueue: Failed to create consumer queue " "from producer queue: queue_id=%d.", producer_queue_->id()); return -ENOMEM; } extern "C" { *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue)); return 0; } void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) { int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer, if (write_queue != nullptr && write_queue->native_window != nullptr) int* out_fence_fd) { ANativeWindow_release(write_queue->native_window); size_t slot; pdx::LocalHandle fence; std::shared_ptr<BufferProducer> buffer_producer; // Need to retry N+1 times, where N is total number of buffers in the queue. // As in the worst case, we will dequeue all N buffers and reallocate them, on // the {N+1}th dequeue, we are guaranteed to get a buffer with new dimension. size_t max_retries = 1 + producer_queue_->capacity(); size_t retry = 0; for (; retry < max_retries; retry++) { auto buffer_status = producer_queue_->Dequeue(timeout, &slot, &fence); if (!buffer_status) { ALOGE_IF(buffer_status.error() != ETIMEDOUT, "DvrWriteBufferQueue::Dequeue: Failed to dequeue buffer: %s", buffer_status.GetErrorMessage().c_str()); return -buffer_status.error(); } buffer_producer = buffer_status.take(); if (!buffer_producer) return -ENOMEM; if (width_ == buffer_producer->width() && height_ == buffer_producer->height() && format_ == buffer_producer->format()) { // Producer queue returns a buffer matches the current request. break; } // Needs reallocation. Note that if there are already multiple available // buffers in the queue, the next one returned from |queue_->Dequeue| may // still have the old buffer dimension or format. Retry up to N+1 times or // until we dequeued a buffer with new configuration. ALOGD_IF(TRACE, "DvrWriteBufferQueue::Dequeue: requested buffer at slot: %zu " "(w=%u, h=%u, fmt=%u) is different from the buffer returned " "(w=%u, h=%u, fmt=%u). Need re-allocation.", slot, width_, height_, format_, buffer_producer->width(), buffer_producer->height(), buffer_producer->format()); // Currently, we are not storing |layer_count| and |usage| in queue // configuration. Copy those setup from the last buffer dequeued before we // remove it. uint32_t old_layer_count = buffer_producer->layer_count(); uint64_t old_usage = buffer_producer->usage(); // Allocate a new producer buffer with new buffer configs. Note that if // there are already multiple available buffers in the queue, the next one // returned from |queue_->Dequeue| may still have the old buffer dimension // or format. Retry up to BufferHubQueue::kMaxQueueCapacity times or until // we dequeued a buffer with new configuration. auto detach_status = producer_queue_->DetachBuffer(slot); if (!detach_status) { ALOGE("DvrWriteBufferQueue::Dequeue: Failed to detach buffer: %s", detach_status.GetErrorMessage().c_str()); return -detach_status.error(); } auto allocate_status = producer_queue_->AllocateBuffer( width_, height_, old_layer_count, format_, old_usage, &slot); if (!allocate_status) { ALOGE("DvrWriteBufferQueue::Dequeue: Failed to allocate buffer: %s", allocate_status.GetErrorMessage().c_str()); return -allocate_status.error(); } } if (retry >= max_retries) { ALOGE( "DvrWriteBufferQueue::Dequeue: Failed to re-allocate buffer after " "resizing."); return -ENOMEM; } write_buffer->write_buffer = std::move(buffer_producer); *out_fence_fd = fence.Release(); return 0; } int DvrWriteBufferQueue::ResizeBuffer(uint32_t width, uint32_t height) { if (width == 0 || height == 0) { ALOGE( "DvrWriteBufferQueue::ResizeBuffer: invalid buffer dimension: w=%u, " "h=%u.", width, height); return -EINVAL; } width_ = width; height_ = height; return 0; } void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) { delete write_queue; delete write_queue; } } ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) { ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) { if (!write_queue || !write_queue->producer_queue) if (!write_queue) return -EINVAL; return -EINVAL; return write_queue->producer_queue->capacity(); return write_queue->capacity(); } } int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue) { int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue) { if (!write_queue) if (!write_queue) return -EINVAL; return -EINVAL; return write_queue->producer_queue->id(); return write_queue->id(); } } int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue, int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue, Loading @@ -63,74 +177,81 @@ int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue, if (!write_queue || !out_window) if (!write_queue || !out_window) return -EINVAL; return -EINVAL; if (write_queue->producer_queue->metadata_size() != return write_queue->GetNativeWindow(out_window); sizeof(DvrNativeBufferMetadata)) { ALOGE( "The size of buffer metadata (%zu) of the write queue does not match " "of size of DvrNativeBufferMetadata (%zu).", write_queue->producer_queue->metadata_size(), sizeof(DvrNativeBufferMetadata)); return -EINVAL; } } // Lazy creation of |native_window|. int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue, if (write_queue->native_window == nullptr) { DvrReadBufferQueue** out_read_queue) { sp<IGraphicBufferProducer> gbp = if (!write_queue || !out_read_queue) dvr::BufferHubQueueProducer::Create(write_queue->producer_queue); return -EINVAL; sp<Surface> surface = new Surface(gbp, true); write_queue->native_window = static_cast<ANativeWindow*>(surface.get()); return write_queue->CreateReadQueue(out_read_queue); ANativeWindow_acquire(write_queue->native_window); } } *out_window = write_queue->native_window; int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout, return 0; DvrWriteBuffer* write_buffer, int* out_fence_fd) { if (!write_queue || !write_buffer || !out_fence_fd) return -EINVAL; return write_queue->Dequeue(timeout, write_buffer, out_fence_fd); } } int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue, int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue, DvrReadBufferQueue** out_read_queue) { uint32_t width, uint32_t height) { if (!write_queue || !write_queue->producer_queue || !out_read_queue) if (!write_queue) return -EINVAL; return -EINVAL; auto read_queue = std::make_unique<DvrReadBufferQueue>(); return write_queue->ResizeBuffer(width, height); read_queue->consumer_queue = } write_queue->producer_queue->CreateConsumerQueue(); if (read_queue->consumer_queue == nullptr) { // ReadBufferQueue DvrReadBufferQueue::DvrReadBufferQueue( const std::shared_ptr<ConsumerQueue>& consumer_queue) : consumer_queue_(consumer_queue) {} int DvrReadBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) { std::unique_ptr<ConsumerQueue> consumer_queue = consumer_queue_->CreateConsumerQueue(); if (consumer_queue == nullptr) { ALOGE( ALOGE( "dvrWriteBufferQueueCreateReadQueue: Failed to create consumer queue " "DvrReadBufferQueue::CreateReadQueue: Failed to create consumer queue " "from DvrWriteBufferQueue[%p].", "from producer queue: queue_id=%d.", consumer_queue_->id()); write_queue); return -ENOMEM; return -ENOMEM; } } *out_read_queue = read_queue.release(); *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue)); return 0; return 0; } } int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout, int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer, DvrWriteBuffer* write_buffer, int* out_fence_fd, void* out_meta, int* out_fence_fd) { size_t meta_size_bytes) { if (!write_queue || !write_queue->producer_queue || !write_buffer || if (meta_size_bytes != consumer_queue_->metadata_size()) { !out_fence_fd) { ALOGE( "DvrReadBufferQueue::Dequeue: Invalid metadata size, expected (%zu), " "but actual (%zu).", consumer_queue_->metadata_size(), meta_size_bytes); return -EINVAL; return -EINVAL; } } size_t slot; size_t slot; pdx::LocalHandle release_fence; pdx::LocalHandle acquire_fence; auto buffer_status = auto buffer_status = consumer_queue_->Dequeue( write_queue->producer_queue->Dequeue(timeout, &slot, &release_fence); timeout, &slot, out_meta, meta_size_bytes, &acquire_fence); if (!buffer_status) { if (!buffer_status) { ALOGE_IF(buffer_status.error() != ETIMEDOUT, ALOGE_IF(buffer_status.error() != ETIMEDOUT, "dvrWriteBufferQueueDequeue: Failed to dequeue buffer: %s", "dvrReadBufferQueueDequeue: Failed to dequeue buffer: %s", buffer_status.GetErrorMessage().c_str()); buffer_status.GetErrorMessage().c_str()); return -buffer_status.error(); return -buffer_status.error(); } } write_buffer->write_buffer = buffer_status.take(); read_buffer->read_buffer = buffer_status.take(); *out_fence_fd = release_fence.Release(); *out_fence_fd = acquire_fence.Release(); return 0; return 0; } } // ReadBufferQueue void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) { void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) { delete read_queue; delete read_queue; } } Loading @@ -139,66 +260,32 @@ ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) { if (!read_queue) if (!read_queue) return -EINVAL; return -EINVAL; return read_queue->consumer_queue->capacity(); return read_queue->capacity(); } } int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) { int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) { if (!read_queue) if (!read_queue) return -EINVAL; return -EINVAL; return read_queue->consumer_queue->id(); return read_queue->id(); } } int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue, int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue, DvrReadBufferQueue** out_read_queue) { DvrReadBufferQueue** out_read_queue) { if (!read_queue || !read_queue->consumer_queue || !out_read_queue) if (!read_queue || !out_read_queue) return -EINVAL; return -EINVAL; auto new_read_queue = std::make_unique<DvrReadBufferQueue>(); return read_queue->CreateReadQueue(out_read_queue); new_read_queue->consumer_queue = read_queue->consumer_queue->CreateConsumerQueue(); if (new_read_queue->consumer_queue == nullptr) { ALOGE( "dvrReadBufferQueueCreateReadQueue: Failed to create consumer queue " "from DvrReadBufferQueue[%p].", read_queue); return -ENOMEM; } *out_read_queue = new_read_queue.release(); return 0; } } int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout, int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout, DvrReadBuffer* read_buffer, int* out_fence_fd, DvrReadBuffer* read_buffer, int* out_fence_fd, void* out_meta, size_t meta_size_bytes) { void* out_meta, size_t meta_size_bytes) { if (!read_queue || !read_queue->consumer_queue || !read_buffer || if (!read_queue || !read_buffer || !out_fence_fd || !out_meta) !out_fence_fd || !out_meta) { return -EINVAL; return -EINVAL; } if (meta_size_bytes != read_queue->consumer_queue->metadata_size()) { ALOGE( "dvrReadBufferQueueDequeue: Invalid metadata size, expected (%zu), " "but actual (%zu).", read_queue->consumer_queue->metadata_size(), meta_size_bytes); return -EINVAL; } size_t slot; return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta, pdx::LocalHandle acquire_fence; meta_size_bytes); auto buffer_status = read_queue->consumer_queue->Dequeue( timeout, &slot, out_meta, meta_size_bytes, &acquire_fence); if (!buffer_status) { ALOGE_IF(buffer_status.error() != ETIMEDOUT, "dvrReadBufferQueueDequeue: Failed to dequeue buffer: %s", buffer_status.GetErrorMessage().c_str()); return -buffer_status.error(); } read_buffer->read_buffer = buffer_status.take(); *out_fence_fd = acquire_fence.Release(); return 0; } } } // extern "C" } // extern "C" Loading
libs/vr/libdisplay/display_client.cpp +10 −3 Original line number Original line Diff line number Diff line Loading @@ -104,9 +104,16 @@ Status<void> Surface::SetAttributes(const SurfaceAttributes& attributes) { return {}; return {}; } } Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue() { Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue(uint32_t width, uint32_t height, uint32_t format) { ALOGD_IF(TRACE, "Surface::CreateQueue: Creating empty queue."); ALOGD_IF(TRACE, "Surface::CreateQueue: Creating empty queue."); auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>(0); auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>( ProducerQueueConfigBuilder() .SetDefaultWidth(width) .SetDefaultHeight(height) .SetDefaultFormat(format) .Build()); if (!status) { if (!status) { ALOGE("Surface::CreateQueue: Failed to create queue: %s", ALOGE("Surface::CreateQueue: Failed to create queue: %s", status.GetErrorMessage().c_str()); status.GetErrorMessage().c_str()); Loading @@ -129,7 +136,7 @@ Status<std::unique_ptr<ProducerQueue>> Surface::CreateQueue( "Surface::CreateQueue: width=%u height=%u layer_count=%u format=%u " "Surface::CreateQueue: width=%u height=%u layer_count=%u format=%u " "usage=%" PRIx64 " capacity=%zu", "usage=%" PRIx64 " capacity=%zu", width, height, layer_count, format, usage, capacity); width, height, layer_count, format, usage, capacity); auto status = CreateQueue(); auto status = CreateQueue(width, height, format); if (!status) if (!status) return status.error_status(); return status.error_status(); Loading
libs/vr/libdisplay/include/private/dvr/display_client.h +3 −1 Original line number Original line Diff line number Diff line Loading @@ -37,7 +37,9 @@ class Surface : public pdx::ClientBase<Surface> { pdx::Status<void> SetAttributes(const SurfaceAttributes& attributes); pdx::Status<void> SetAttributes(const SurfaceAttributes& attributes); // Creates an empty queue. // Creates an empty queue. pdx::Status<std::unique_ptr<ProducerQueue>> CreateQueue(); pdx::Status<std::unique_ptr<ProducerQueue>> CreateQueue(uint32_t width, uint32_t height, uint32_t format); // Creates a queue and populates it with |capacity| buffers of the specified // Creates a queue and populates it with |capacity| buffers of the specified // parameters. // parameters. Loading
libs/vr/libdisplay/include/private/dvr/display_protocol.h +3 −2 Original line number Original line Diff line number Diff line Loading @@ -222,8 +222,9 @@ struct DisplayProtocol { PDX_REMOTE_METHOD(CreateSurface, kOpCreateSurface, PDX_REMOTE_METHOD(CreateSurface, kOpCreateSurface, SurfaceInfo(const SurfaceAttributes& attributes)); SurfaceInfo(const SurfaceAttributes& attributes)); PDX_REMOTE_METHOD(GetSurfaceInfo, kOpGetSurfaceInfo, SurfaceInfo(Void)); PDX_REMOTE_METHOD(GetSurfaceInfo, kOpGetSurfaceInfo, SurfaceInfo(Void)); PDX_REMOTE_METHOD(CreateQueue, kOpCreateQueue, PDX_REMOTE_METHOD( LocalChannelHandle(size_t meta_size_bytes)); CreateQueue, kOpCreateQueue, LocalChannelHandle(const ProducerQueueConfig& producer_config)); PDX_REMOTE_METHOD(SetAttributes, kOpSetAttributes, PDX_REMOTE_METHOD(SetAttributes, kOpSetAttributes, void(const SurfaceAttributes& attributes)); void(const SurfaceAttributes& attributes)); }; }; Loading
libs/vr/libdvr/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,7 @@ cc_library_headers { cflags = [ cflags = [ "-DLOG_TAG=\"libdvr\"", "-DLOG_TAG=\"libdvr\"", "-DTRACE=0", ] ] srcs = [ srcs = [ Loading
libs/vr/libdvr/dvr_buffer_queue.cpp +195 −108 Original line number Original line Diff line number Diff line Loading @@ -2,60 +2,174 @@ #include "include/dvr/dvr_buffer_queue.h" #include "include/dvr/dvr_buffer_queue.h" #include <android/native_window.h> #include <android/native_window.h> #include <gui/Surface.h> #include <private/dvr/buffer_hub_queue_client.h> #include <private/dvr/buffer_hub_queue_producer.h> #include <private/dvr/buffer_hub_queue_producer.h> #include "dvr_internal.h" #include "dvr_internal.h" #include "dvr_buffer_queue_internal.h" #define CHECK_PARAM(param) \ LOG_ALWAYS_FATAL_IF(param == nullptr, "%s: " #param "cannot be NULL.", \ __FUNCTION__) using namespace android; using namespace android; using android::dvr::BufferHubQueueProducer; using android::dvr::BufferProducer; using android::dvr::ConsumerQueue; using android::dvr::ProducerQueue; extern "C" { namespace android { DvrWriteBufferQueue::DvrWriteBufferQueue( namespace dvr { const std::shared_ptr<ProducerQueue>& producer_queue) : producer_queue_(producer_queue), width_(producer_queue->default_width()), height_(producer_queue->default_height()), format_(producer_queue->default_format()) {} DvrWriteBufferQueue* CreateDvrWriteBufferQueueFromProducerQueue( int DvrWriteBufferQueue::GetNativeWindow(ANativeWindow** out_window) { const std::shared_ptr<dvr::ProducerQueue>& producer_queue) { if (producer_queue_->metadata_size() != sizeof(DvrNativeBufferMetadata)) { return new DvrWriteBufferQueue{std::move(producer_queue)}; ALOGE( "DvrWriteBufferQueue::GetNativeWindow: The size of buffer metadata " "(%zu) of the write queue does not match of size of " "DvrNativeBufferMetadata (%zu).", producer_queue_->metadata_size(), sizeof(DvrNativeBufferMetadata)); return -EINVAL; } } DvrReadBufferQueue* CreateDvrReadBufferQueueFromConsumerQueue( if (native_window_ == nullptr) { const std::shared_ptr<dvr::ConsumerQueue>& consumer_queue) { // Lazy creation of |native_window|, as not everyone is using return new DvrReadBufferQueue{std::move(consumer_queue)}; // DvrWriteBufferQueue as an external surface. sp<IGraphicBufferProducer> gbp = BufferHubQueueProducer::Create(producer_queue_); native_window_ = new Surface(gbp, true); } } dvr::ProducerQueue* GetProducerQueueFromDvrWriteBufferQueue( *out_window = static_cast<ANativeWindow*>(native_window_.get()); DvrWriteBufferQueue* write_queue) { return 0; return write_queue->producer_queue.get(); } } } // namespace dvr int DvrWriteBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) { } // namespace android std::unique_ptr<ConsumerQueue> consumer_queue = producer_queue_->CreateConsumerQueue(); if (consumer_queue == nullptr) { ALOGE( "DvrWriteBufferQueue::CreateReadQueue: Failed to create consumer queue " "from producer queue: queue_id=%d.", producer_queue_->id()); return -ENOMEM; } extern "C" { *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue)); return 0; } void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) { int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer, if (write_queue != nullptr && write_queue->native_window != nullptr) int* out_fence_fd) { ANativeWindow_release(write_queue->native_window); size_t slot; pdx::LocalHandle fence; std::shared_ptr<BufferProducer> buffer_producer; // Need to retry N+1 times, where N is total number of buffers in the queue. // As in the worst case, we will dequeue all N buffers and reallocate them, on // the {N+1}th dequeue, we are guaranteed to get a buffer with new dimension. size_t max_retries = 1 + producer_queue_->capacity(); size_t retry = 0; for (; retry < max_retries; retry++) { auto buffer_status = producer_queue_->Dequeue(timeout, &slot, &fence); if (!buffer_status) { ALOGE_IF(buffer_status.error() != ETIMEDOUT, "DvrWriteBufferQueue::Dequeue: Failed to dequeue buffer: %s", buffer_status.GetErrorMessage().c_str()); return -buffer_status.error(); } buffer_producer = buffer_status.take(); if (!buffer_producer) return -ENOMEM; if (width_ == buffer_producer->width() && height_ == buffer_producer->height() && format_ == buffer_producer->format()) { // Producer queue returns a buffer matches the current request. break; } // Needs reallocation. Note that if there are already multiple available // buffers in the queue, the next one returned from |queue_->Dequeue| may // still have the old buffer dimension or format. Retry up to N+1 times or // until we dequeued a buffer with new configuration. ALOGD_IF(TRACE, "DvrWriteBufferQueue::Dequeue: requested buffer at slot: %zu " "(w=%u, h=%u, fmt=%u) is different from the buffer returned " "(w=%u, h=%u, fmt=%u). Need re-allocation.", slot, width_, height_, format_, buffer_producer->width(), buffer_producer->height(), buffer_producer->format()); // Currently, we are not storing |layer_count| and |usage| in queue // configuration. Copy those setup from the last buffer dequeued before we // remove it. uint32_t old_layer_count = buffer_producer->layer_count(); uint64_t old_usage = buffer_producer->usage(); // Allocate a new producer buffer with new buffer configs. Note that if // there are already multiple available buffers in the queue, the next one // returned from |queue_->Dequeue| may still have the old buffer dimension // or format. Retry up to BufferHubQueue::kMaxQueueCapacity times or until // we dequeued a buffer with new configuration. auto detach_status = producer_queue_->DetachBuffer(slot); if (!detach_status) { ALOGE("DvrWriteBufferQueue::Dequeue: Failed to detach buffer: %s", detach_status.GetErrorMessage().c_str()); return -detach_status.error(); } auto allocate_status = producer_queue_->AllocateBuffer( width_, height_, old_layer_count, format_, old_usage, &slot); if (!allocate_status) { ALOGE("DvrWriteBufferQueue::Dequeue: Failed to allocate buffer: %s", allocate_status.GetErrorMessage().c_str()); return -allocate_status.error(); } } if (retry >= max_retries) { ALOGE( "DvrWriteBufferQueue::Dequeue: Failed to re-allocate buffer after " "resizing."); return -ENOMEM; } write_buffer->write_buffer = std::move(buffer_producer); *out_fence_fd = fence.Release(); return 0; } int DvrWriteBufferQueue::ResizeBuffer(uint32_t width, uint32_t height) { if (width == 0 || height == 0) { ALOGE( "DvrWriteBufferQueue::ResizeBuffer: invalid buffer dimension: w=%u, " "h=%u.", width, height); return -EINVAL; } width_ = width; height_ = height; return 0; } void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) { delete write_queue; delete write_queue; } } ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) { ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) { if (!write_queue || !write_queue->producer_queue) if (!write_queue) return -EINVAL; return -EINVAL; return write_queue->producer_queue->capacity(); return write_queue->capacity(); } } int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue) { int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue) { if (!write_queue) if (!write_queue) return -EINVAL; return -EINVAL; return write_queue->producer_queue->id(); return write_queue->id(); } } int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue, int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue, Loading @@ -63,74 +177,81 @@ int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue, if (!write_queue || !out_window) if (!write_queue || !out_window) return -EINVAL; return -EINVAL; if (write_queue->producer_queue->metadata_size() != return write_queue->GetNativeWindow(out_window); sizeof(DvrNativeBufferMetadata)) { ALOGE( "The size of buffer metadata (%zu) of the write queue does not match " "of size of DvrNativeBufferMetadata (%zu).", write_queue->producer_queue->metadata_size(), sizeof(DvrNativeBufferMetadata)); return -EINVAL; } } // Lazy creation of |native_window|. int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue, if (write_queue->native_window == nullptr) { DvrReadBufferQueue** out_read_queue) { sp<IGraphicBufferProducer> gbp = if (!write_queue || !out_read_queue) dvr::BufferHubQueueProducer::Create(write_queue->producer_queue); return -EINVAL; sp<Surface> surface = new Surface(gbp, true); write_queue->native_window = static_cast<ANativeWindow*>(surface.get()); return write_queue->CreateReadQueue(out_read_queue); ANativeWindow_acquire(write_queue->native_window); } } *out_window = write_queue->native_window; int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout, return 0; DvrWriteBuffer* write_buffer, int* out_fence_fd) { if (!write_queue || !write_buffer || !out_fence_fd) return -EINVAL; return write_queue->Dequeue(timeout, write_buffer, out_fence_fd); } } int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue, int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue, DvrReadBufferQueue** out_read_queue) { uint32_t width, uint32_t height) { if (!write_queue || !write_queue->producer_queue || !out_read_queue) if (!write_queue) return -EINVAL; return -EINVAL; auto read_queue = std::make_unique<DvrReadBufferQueue>(); return write_queue->ResizeBuffer(width, height); read_queue->consumer_queue = } write_queue->producer_queue->CreateConsumerQueue(); if (read_queue->consumer_queue == nullptr) { // ReadBufferQueue DvrReadBufferQueue::DvrReadBufferQueue( const std::shared_ptr<ConsumerQueue>& consumer_queue) : consumer_queue_(consumer_queue) {} int DvrReadBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) { std::unique_ptr<ConsumerQueue> consumer_queue = consumer_queue_->CreateConsumerQueue(); if (consumer_queue == nullptr) { ALOGE( ALOGE( "dvrWriteBufferQueueCreateReadQueue: Failed to create consumer queue " "DvrReadBufferQueue::CreateReadQueue: Failed to create consumer queue " "from DvrWriteBufferQueue[%p].", "from producer queue: queue_id=%d.", consumer_queue_->id()); write_queue); return -ENOMEM; return -ENOMEM; } } *out_read_queue = read_queue.release(); *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue)); return 0; return 0; } } int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout, int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer, DvrWriteBuffer* write_buffer, int* out_fence_fd, void* out_meta, int* out_fence_fd) { size_t meta_size_bytes) { if (!write_queue || !write_queue->producer_queue || !write_buffer || if (meta_size_bytes != consumer_queue_->metadata_size()) { !out_fence_fd) { ALOGE( "DvrReadBufferQueue::Dequeue: Invalid metadata size, expected (%zu), " "but actual (%zu).", consumer_queue_->metadata_size(), meta_size_bytes); return -EINVAL; return -EINVAL; } } size_t slot; size_t slot; pdx::LocalHandle release_fence; pdx::LocalHandle acquire_fence; auto buffer_status = auto buffer_status = consumer_queue_->Dequeue( write_queue->producer_queue->Dequeue(timeout, &slot, &release_fence); timeout, &slot, out_meta, meta_size_bytes, &acquire_fence); if (!buffer_status) { if (!buffer_status) { ALOGE_IF(buffer_status.error() != ETIMEDOUT, ALOGE_IF(buffer_status.error() != ETIMEDOUT, "dvrWriteBufferQueueDequeue: Failed to dequeue buffer: %s", "dvrReadBufferQueueDequeue: Failed to dequeue buffer: %s", buffer_status.GetErrorMessage().c_str()); buffer_status.GetErrorMessage().c_str()); return -buffer_status.error(); return -buffer_status.error(); } } write_buffer->write_buffer = buffer_status.take(); read_buffer->read_buffer = buffer_status.take(); *out_fence_fd = release_fence.Release(); *out_fence_fd = acquire_fence.Release(); return 0; return 0; } } // ReadBufferQueue void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) { void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) { delete read_queue; delete read_queue; } } Loading @@ -139,66 +260,32 @@ ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) { if (!read_queue) if (!read_queue) return -EINVAL; return -EINVAL; return read_queue->consumer_queue->capacity(); return read_queue->capacity(); } } int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) { int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) { if (!read_queue) if (!read_queue) return -EINVAL; return -EINVAL; return read_queue->consumer_queue->id(); return read_queue->id(); } } int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue, int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue, DvrReadBufferQueue** out_read_queue) { DvrReadBufferQueue** out_read_queue) { if (!read_queue || !read_queue->consumer_queue || !out_read_queue) if (!read_queue || !out_read_queue) return -EINVAL; return -EINVAL; auto new_read_queue = std::make_unique<DvrReadBufferQueue>(); return read_queue->CreateReadQueue(out_read_queue); new_read_queue->consumer_queue = read_queue->consumer_queue->CreateConsumerQueue(); if (new_read_queue->consumer_queue == nullptr) { ALOGE( "dvrReadBufferQueueCreateReadQueue: Failed to create consumer queue " "from DvrReadBufferQueue[%p].", read_queue); return -ENOMEM; } *out_read_queue = new_read_queue.release(); return 0; } } int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout, int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout, DvrReadBuffer* read_buffer, int* out_fence_fd, DvrReadBuffer* read_buffer, int* out_fence_fd, void* out_meta, size_t meta_size_bytes) { void* out_meta, size_t meta_size_bytes) { if (!read_queue || !read_queue->consumer_queue || !read_buffer || if (!read_queue || !read_buffer || !out_fence_fd || !out_meta) !out_fence_fd || !out_meta) { return -EINVAL; return -EINVAL; } if (meta_size_bytes != read_queue->consumer_queue->metadata_size()) { ALOGE( "dvrReadBufferQueueDequeue: Invalid metadata size, expected (%zu), " "but actual (%zu).", read_queue->consumer_queue->metadata_size(), meta_size_bytes); return -EINVAL; } size_t slot; return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta, pdx::LocalHandle acquire_fence; meta_size_bytes); auto buffer_status = read_queue->consumer_queue->Dequeue( timeout, &slot, out_meta, meta_size_bytes, &acquire_fence); if (!buffer_status) { ALOGE_IF(buffer_status.error() != ETIMEDOUT, "dvrReadBufferQueueDequeue: Failed to dequeue buffer: %s", buffer_status.GetErrorMessage().c_str()); return -buffer_status.error(); } read_buffer->read_buffer = buffer_status.take(); *out_fence_fd = acquire_fence.Release(); return 0; } } } // extern "C" } // extern "C"