DvrWriteBufferQueue: support buffer resizing
Currently, the buffer resising is implemented at the C API's
implementation level, i.e. it's a pure client side logic out of the core
BufferHubQueue C++/PDX implementation. The logic is similar to
BufferHubQueueProducer's buffer resizing logic.
Other minor changes:
1/ Use ProducerQueueConfig in DisplaySurface as well, and plumb default
width, height, and format to bufferhubd when a BufferHubQueue is created
through a Display Surface.
2/ Added detailed dvr_buffer_queue comments.
3/ Since we now have more and more logic in dvr_buffer_queue, refactored
Dvr{Read,Write}BufferQueue to be C++-styled class.
Bug: 38324405
Test: buffer_hub_queue_producer-test, buffer_hub_queue-test, dvr_api-test
Change-Id: I7186fc04e84eafda46eca316a94739bb3b5c07ca
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index 5a0c3d0..fbb39f3 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -104,9 +104,16 @@
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.");
- auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>(0);
+ auto status = InvokeRemoteMethod<DisplayProtocol::CreateQueue>(
+ ProducerQueueConfigBuilder()
+ .SetDefaultWidth(width)
+ .SetDefaultHeight(height)
+ .SetDefaultFormat(format)
+ .Build());
if (!status) {
ALOGE("Surface::CreateQueue: Failed to create queue: %s",
status.GetErrorMessage().c_str());
@@ -129,7 +136,7 @@
"Surface::CreateQueue: width=%u height=%u layer_count=%u format=%u "
"usage=%" PRIx64 " capacity=%zu",
width, height, layer_count, format, usage, capacity);
- auto status = CreateQueue();
+ auto status = CreateQueue(width, height, format);
if (!status)
return status.error_status();
diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h
index e5b3340..61883ce 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_client.h
@@ -37,7 +37,9 @@
pdx::Status<void> SetAttributes(const SurfaceAttributes& attributes);
// 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
// parameters.
diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
index b857d48..cfbda7a 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
@@ -213,8 +213,9 @@
PDX_REMOTE_METHOD(CreateSurface, kOpCreateSurface,
SurfaceInfo(const SurfaceAttributes& attributes));
PDX_REMOTE_METHOD(GetSurfaceInfo, kOpGetSurfaceInfo, SurfaceInfo(Void));
- PDX_REMOTE_METHOD(CreateQueue, kOpCreateQueue,
- LocalChannelHandle(size_t meta_size_bytes));
+ PDX_REMOTE_METHOD(
+ CreateQueue, kOpCreateQueue,
+ LocalChannelHandle(const ProducerQueueConfig& producer_config));
PDX_REMOTE_METHOD(SetAttributes, kOpSetAttributes,
void(const SurfaceAttributes& attributes));
};
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 2b4ebbe..a788cce 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -21,6 +21,7 @@
cflags = [
"-DLOG_TAG=\"libdvr\"",
+ "-DTRACE=0",
]
srcs = [
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index f668510..d76eaf6 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -2,60 +2,174 @@
#include "include/dvr/dvr_buffer_queue.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 "dvr_internal.h"
-
-#define CHECK_PARAM(param) \
- LOG_ALWAYS_FATAL_IF(param == nullptr, "%s: " #param "cannot be NULL.", \
- __FUNCTION__)
+#include "dvr_buffer_queue_internal.h"
using namespace android;
-
-namespace android {
-namespace dvr {
-
-DvrWriteBufferQueue* CreateDvrWriteBufferQueueFromProducerQueue(
- const std::shared_ptr<dvr::ProducerQueue>& producer_queue) {
- return new DvrWriteBufferQueue{std::move(producer_queue)};
-}
-
-DvrReadBufferQueue* CreateDvrReadBufferQueueFromConsumerQueue(
- const std::shared_ptr<dvr::ConsumerQueue>& consumer_queue) {
- return new DvrReadBufferQueue{std::move(consumer_queue)};
-}
-
-dvr::ProducerQueue* GetProducerQueueFromDvrWriteBufferQueue(
- DvrWriteBufferQueue* write_queue) {
- return write_queue->producer_queue.get();
-}
-
-} // namespace dvr
-} // namespace android
+using android::dvr::BufferHubQueueProducer;
+using android::dvr::BufferProducer;
+using android::dvr::ConsumerQueue;
+using android::dvr::ProducerQueue;
extern "C" {
-void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue) {
- if (write_queue != nullptr && write_queue->native_window != nullptr)
- ANativeWindow_release(write_queue->native_window);
+DvrWriteBufferQueue::DvrWriteBufferQueue(
+ 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()) {}
+int DvrWriteBufferQueue::GetNativeWindow(ANativeWindow** out_window) {
+ if (producer_queue_->metadata_size() != sizeof(DvrNativeBufferMetadata)) {
+ 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;
+ }
+
+ if (native_window_ == nullptr) {
+ // Lazy creation of |native_window|, as not everyone is using
+ // DvrWriteBufferQueue as an external surface.
+ sp<IGraphicBufferProducer> gbp =
+ BufferHubQueueProducer::Create(producer_queue_);
+ native_window_ = new Surface(gbp, true);
+ }
+
+ *out_window = static_cast<ANativeWindow*>(native_window_.get());
+ return 0;
+}
+
+int DvrWriteBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
+ 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;
+ }
+
+ *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
+ return 0;
+}
+
+int DvrWriteBufferQueue::Dequeue(int timeout, DvrWriteBuffer* write_buffer,
+ int* out_fence_fd) {
+ 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;
}
ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue) {
- if (!write_queue || !write_queue->producer_queue)
+ if (!write_queue)
return -EINVAL;
- return write_queue->producer_queue->capacity();
+ return write_queue->capacity();
}
int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue) {
if (!write_queue)
return -EINVAL;
- return write_queue->producer_queue->id();
+ return write_queue->id();
}
int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
@@ -63,131 +177,68 @@
if (!write_queue || !out_window)
return -EINVAL;
- if (write_queue->producer_queue->metadata_size() !=
- 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|.
- if (write_queue->native_window == nullptr) {
- sp<IGraphicBufferProducer> gbp =
- dvr::BufferHubQueueProducer::Create(write_queue->producer_queue);
- sp<Surface> surface = new Surface(gbp, true);
- write_queue->native_window = static_cast<ANativeWindow*>(surface.get());
- ANativeWindow_acquire(write_queue->native_window);
- }
-
- *out_window = write_queue->native_window;
- return 0;
+ return write_queue->GetNativeWindow(out_window);
}
int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
DvrReadBufferQueue** out_read_queue) {
- if (!write_queue || !write_queue->producer_queue || !out_read_queue)
+ if (!write_queue || !out_read_queue)
return -EINVAL;
- auto read_queue = std::make_unique<DvrReadBufferQueue>();
- read_queue->consumer_queue =
- write_queue->producer_queue->CreateConsumerQueue();
- if (read_queue->consumer_queue == nullptr) {
- ALOGE(
- "dvrWriteBufferQueueCreateReadQueue: Failed to create consumer queue "
- "from DvrWriteBufferQueue[%p].",
- write_queue);
- return -ENOMEM;
- }
-
- *out_read_queue = read_queue.release();
- return 0;
+ return write_queue->CreateReadQueue(out_read_queue);
}
int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
DvrWriteBuffer* write_buffer,
int* out_fence_fd) {
- if (!write_queue || !write_queue->producer_queue || !write_buffer ||
- !out_fence_fd) {
+ if (!write_queue || !write_buffer || !out_fence_fd)
return -EINVAL;
- }
- size_t slot;
- pdx::LocalHandle release_fence;
- auto buffer_status =
- write_queue->producer_queue->Dequeue(timeout, &slot, &release_fence);
- if (!buffer_status) {
- ALOGE_IF(buffer_status.error() != ETIMEDOUT,
- "dvrWriteBufferQueueDequeue: Failed to dequeue buffer: %s",
- buffer_status.GetErrorMessage().c_str());
- return -buffer_status.error();
- }
+ return write_queue->Dequeue(timeout, write_buffer, out_fence_fd);
+}
- write_buffer->write_buffer = buffer_status.take();
- *out_fence_fd = release_fence.Release();
- return 0;
+int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue,
+ uint32_t width, uint32_t height) {
+ if (!write_queue)
+ return -EINVAL;
+
+ return write_queue->ResizeBuffer(width, height);
}
// ReadBufferQueue
-void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
- delete read_queue;
-}
-ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) {
- if (!read_queue)
- return -EINVAL;
+DvrReadBufferQueue::DvrReadBufferQueue(
+ const std::shared_ptr<ConsumerQueue>& consumer_queue)
+ : consumer_queue_(consumer_queue) {}
- return read_queue->consumer_queue->capacity();
-}
-
-int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) {
- if (!read_queue)
- return -EINVAL;
-
- return read_queue->consumer_queue->id();
-}
-
-int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
- DvrReadBufferQueue** out_read_queue) {
- if (!read_queue || !read_queue->consumer_queue || !out_read_queue)
- return -EINVAL;
-
- auto new_read_queue = std::make_unique<DvrReadBufferQueue>();
- new_read_queue->consumer_queue =
- read_queue->consumer_queue->CreateConsumerQueue();
- if (new_read_queue->consumer_queue == nullptr) {
+int DvrReadBufferQueue::CreateReadQueue(DvrReadBufferQueue** out_read_queue) {
+ std::unique_ptr<ConsumerQueue> consumer_queue =
+ consumer_queue_->CreateConsumerQueue();
+ if (consumer_queue == nullptr) {
ALOGE(
- "dvrReadBufferQueueCreateReadQueue: Failed to create consumer queue "
- "from DvrReadBufferQueue[%p].",
- read_queue);
+ "DvrReadBufferQueue::CreateReadQueue: Failed to create consumer queue "
+ "from producer queue: queue_id=%d.", consumer_queue_->id());
return -ENOMEM;
}
- *out_read_queue = new_read_queue.release();
+ *out_read_queue = new DvrReadBufferQueue(std::move(consumer_queue));
return 0;
}
-int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
- DvrReadBuffer* read_buffer, int* out_fence_fd,
- void* out_meta, size_t meta_size_bytes) {
- if (!read_queue || !read_queue->consumer_queue || !read_buffer ||
- !out_fence_fd || !out_meta) {
- return -EINVAL;
- }
-
- if (meta_size_bytes != read_queue->consumer_queue->metadata_size()) {
+int DvrReadBufferQueue::Dequeue(int timeout, DvrReadBuffer* read_buffer,
+ int* out_fence_fd, void* out_meta,
+ size_t meta_size_bytes) {
+ if (meta_size_bytes != consumer_queue_->metadata_size()) {
ALOGE(
- "dvrReadBufferQueueDequeue: Invalid metadata size, expected (%zu), "
+ "DvrReadBufferQueue::Dequeue: Invalid metadata size, expected (%zu), "
"but actual (%zu).",
- read_queue->consumer_queue->metadata_size(), meta_size_bytes);
+ consumer_queue_->metadata_size(), meta_size_bytes);
return -EINVAL;
}
size_t slot;
pdx::LocalHandle acquire_fence;
- auto buffer_status = read_queue->consumer_queue->Dequeue(
+ auto buffer_status = consumer_queue_->Dequeue(
timeout, &slot, out_meta, meta_size_bytes, &acquire_fence);
if (!buffer_status) {
ALOGE_IF(buffer_status.error() != ETIMEDOUT,
@@ -201,4 +252,40 @@
return 0;
}
+void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue) {
+ delete read_queue;
+}
+
+ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue) {
+ if (!read_queue)
+ return -EINVAL;
+
+ return read_queue->capacity();
+}
+
+int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue) {
+ if (!read_queue)
+ return -EINVAL;
+
+ return read_queue->id();
+}
+
+int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
+ DvrReadBufferQueue** out_read_queue) {
+ if (!read_queue || !out_read_queue)
+ return -EINVAL;
+
+ return read_queue->CreateReadQueue(out_read_queue);
+}
+
+int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
+ DvrReadBuffer* read_buffer, int* out_fence_fd,
+ void* out_meta, size_t meta_size_bytes) {
+ if (!read_queue || !read_buffer || !out_fence_fd || !out_meta)
+ return -EINVAL;
+
+ return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta,
+ meta_size_bytes);
+}
+
} // extern "C"
diff --git a/libs/vr/libdvr/dvr_buffer_queue_internal.h b/libs/vr/libdvr/dvr_buffer_queue_internal.h
new file mode 100644
index 0000000..f012873
--- /dev/null
+++ b/libs/vr/libdvr/dvr_buffer_queue_internal.h
@@ -0,0 +1,62 @@
+#ifndef ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
+#define ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
+
+#include <gui/Surface.h>
+#include <private/dvr/buffer_hub_queue_client.h>
+#include <sys/cdefs.h>
+
+#include <memory>
+
+struct ANativeWindow;
+
+struct DvrWriteBufferQueue {
+ using ProducerQueue = android::dvr::ProducerQueue;
+
+ // Create a concrete object for DvrWriteBufferQueue.
+ //
+ // @param producer_queue The BufferHub's ProducerQueue that is used to back
+ // this DvrWriteBufferQueue, must not be NULL.
+ explicit DvrWriteBufferQueue(
+ const std::shared_ptr<ProducerQueue>& producer_queue);
+
+ int id() const { return producer_queue_->id(); }
+ uint32_t width() const { return width_; };
+ uint32_t height() const { return height_; };
+ uint32_t format() const { return format_; };
+ size_t capacity() const { return producer_queue_->capacity(); }
+ const std::shared_ptr<ProducerQueue>& producer_queue() const {
+ return producer_queue_;
+ }
+
+ int GetNativeWindow(ANativeWindow** out_window);
+ int CreateReadQueue(DvrReadBufferQueue** out_read_queue);
+ int Dequeue(int timeout, DvrWriteBuffer* write_buffer, int* out_fence_fd);
+ int ResizeBuffer(uint32_t width, uint32_t height);
+
+ private:
+ std::shared_ptr<ProducerQueue> producer_queue_;
+
+ uint32_t width_;
+ uint32_t height_;
+ uint32_t format_;
+ android::sp<android::Surface> native_window_;
+};
+
+struct DvrReadBufferQueue {
+ using ConsumerQueue = android::dvr::ConsumerQueue;
+
+ explicit DvrReadBufferQueue(
+ const std::shared_ptr<ConsumerQueue>& consumer_queue);
+
+ int id() const { return consumer_queue_->id(); }
+ size_t capacity() const { return consumer_queue_->capacity(); }
+
+ int CreateReadQueue(DvrReadBufferQueue** out_read_queue);
+ int Dequeue(int timeout, DvrReadBuffer* read_buffer, int* out_fence_fd,
+ void* out_meta, size_t meta_size_bytes);
+
+ private:
+ std::shared_ptr<ConsumerQueue> consumer_queue_;
+};
+
+#endif // ANDROID_DVR_BUFFER_QUEUE_INTERNAL_H_
diff --git a/libs/vr/libdvr/dvr_display_manager.cpp b/libs/vr/libdvr/dvr_display_manager.cpp
index ffe090d..4b53642 100644
--- a/libs/vr/libdvr/dvr_display_manager.cpp
+++ b/libs/vr/libdvr/dvr_display_manager.cpp
@@ -8,6 +8,7 @@
#include <private/dvr/display_manager_client.h>
#include "dvr_internal.h"
+#include "dvr_buffer_queue_internal.h"
using android::AHardwareBuffer_convertToGrallocUsageBits;
using android::dvr::BufferConsumer;
@@ -16,7 +17,6 @@
using android::dvr::display::SurfaceAttributes;
using android::dvr::display::SurfaceAttribute;
using android::dvr::display::SurfaceState;
-using android::dvr::CreateDvrReadBufferQueueFromConsumerQueue;
using android::pdx::rpc::EmptyVariant;
namespace {
@@ -220,7 +220,7 @@
return -status.error();
}
- *queue_out = CreateDvrReadBufferQueueFromConsumerQueue(status.take());
+ *queue_out = new DvrReadBufferQueue(status.take());
return 0;
}
diff --git a/libs/vr/libdvr/dvr_internal.h b/libs/vr/libdvr/dvr_internal.h
index 6431f1c..28b6c28 100644
--- a/libs/vr/libdvr/dvr_internal.h
+++ b/libs/vr/libdvr/dvr_internal.h
@@ -10,8 +10,6 @@
typedef struct DvrBuffer DvrBuffer;
typedef struct DvrReadBuffer DvrReadBuffer;
typedef struct DvrWriteBuffer DvrWriteBuffer;
-typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
-typedef struct DvrReadBufferQueue DvrReadBufferQueue;
} // extern "C"
@@ -20,9 +18,7 @@
class BufferProducer;
class BufferConsumer;
-class ConsumerQueue;
class IonBuffer;
-class ProducerQueue;
DvrBuffer* CreateDvrBufferFromIonBuffer(
const std::shared_ptr<IonBuffer>& ion_buffer);
@@ -32,20 +28,11 @@
DvrWriteBuffer* CreateDvrWriteBufferFromBufferProducer(
const std::shared_ptr<BufferProducer>& buffer_producer);
-DvrReadBufferQueue* CreateDvrReadBufferQueueFromConsumerQueue(
- const std::shared_ptr<ConsumerQueue>& consumer_queue);
-DvrWriteBufferQueue* CreateDvrWriteBufferQueueFromProducerQueue(
- const std::shared_ptr<ProducerQueue>& producer_queue);
-ProducerQueue* GetProducerQueueFromDvrWriteBufferQueue(
- DvrWriteBufferQueue* write_queue);
-
} // namespace dvr
} // namespace android
extern "C" {
-struct ANativeWindow;
-
struct DvrWriteBuffer {
std::shared_ptr<android::dvr::BufferProducer> write_buffer;
};
@@ -58,15 +45,6 @@
std::shared_ptr<android::dvr::IonBuffer> buffer;
};
-struct DvrWriteBufferQueue {
- std::shared_ptr<android::dvr::ProducerQueue> producer_queue;
- ANativeWindow* native_window{nullptr};
-};
-
-struct DvrReadBufferQueue {
- std::shared_ptr<android::dvr::ConsumerQueue> consumer_queue;
-};
-
} // extern "C"
#endif // ANDROID_DVR_INTERNAL_H_
diff --git a/libs/vr/libdvr/dvr_surface.cpp b/libs/vr/libdvr/dvr_surface.cpp
index 1fe9874..2affacd 100644
--- a/libs/vr/libdvr/dvr_surface.cpp
+++ b/libs/vr/libdvr/dvr_surface.cpp
@@ -5,13 +5,13 @@
#include <private/dvr/display_client.h>
#include "dvr_internal.h"
+#include "dvr_buffer_queue_internal.h"
using android::dvr::display::DisplayClient;
using android::dvr::display::Surface;
using android::dvr::display::SurfaceAttributes;
using android::dvr::display::SurfaceAttributeValue;
using android::dvr::CreateDvrReadBufferFromBufferConsumer;
-using android::dvr::CreateDvrWriteBufferQueueFromProducerQueue;
namespace {
@@ -152,7 +152,7 @@
return -status.error();
}
- *out_writer = CreateDvrWriteBufferQueueFromProducerQueue(status.take());
+ *out_writer = new DvrWriteBufferQueue(status.take());
return 0;
}
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
index dd669dc..3165bfc 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
@@ -12,29 +12,122 @@
typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
typedef struct DvrReadBufferQueue DvrReadBufferQueue;
-// WriteBufferQueue
+// Destroy a write buffer queue.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
void dvrWriteBufferQueueDestroy(DvrWriteBufferQueue* write_queue);
+
+// Get the total number of buffers in a write buffer queue.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @return The capacity on success; or negative error code.
ssize_t dvrWriteBufferQueueGetCapacity(DvrWriteBufferQueue* write_queue);
+
+// Get the system unique queue id of a write buffer queue.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @return Queue id on success; or negative error code.
int dvrWriteBufferQueueGetId(DvrWriteBufferQueue* write_queue);
-// Returns ANativeWindow. Can be casted to a Java Surface using
-// ANativeWindow_toSurface NDK API. Note that this method does not acquire an
-// additional reference to the ANativeWindow returned, don't call
-// ANativeWindow_release on it.
+// Gets an ANativeWindow backed by the DvrWriteBufferQueue
+//
+// Can be casted to a Java Surface using ANativeWindow_toSurface NDK API. Note
+// that the native window is lazily created at the first time |GetNativeWindow|
+// is called, and the created ANativeWindow will be cached so that multiple
+// calls to this method will return the same object. Also note that this method
+// does not acquire an additional reference to the ANativeWindow returned, don't
+// call ANativeWindow_release on it.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @param out_window The pointer of an ANativeWindow will be filled here if
+// the method call succeeds.
+// @return Zero on success; or -EINVAL if this DvrWriteBufferQueue does not
+// support being used as an android Surface.
int dvrWriteBufferQueueGetExternalSurface(DvrWriteBufferQueue* write_queue,
ANativeWindow** out_window);
+// Create a read buffer queue from an existing write buffer queue.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @param out_read_queue The pointer of a DvrReadBufferQueue will be filled here
+// if the method call succeeds.
+// @return Zero on success, or negative error code.
int dvrWriteBufferQueueCreateReadQueue(DvrWriteBufferQueue* write_queue,
DvrReadBufferQueue** out_read_queue);
+
+// Dequeue a buffer to write into.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @param timeout Specifies the number of milliseconds that the method will
+// block. Specifying a timeout of -1 causes it to block indefinitely,
+// while specifying a timeout equal to zero cause it to return immediately,
+// even if no buffers are available.
+// @param out_buffer A targeting DvrWriteBuffer object to hold the output of the
+// dequeue operation. Must be created by |dvrWriteBufferCreateEmpty|.
+// @param out_fence_fd A sync fence fd defined in NDK's sync.h API, which
+// signals the release of underlying buffer. The producer should wait until
+// this fence clears before writing data into it.
+// @return Zero on success, or negative error code.
int dvrWriteBufferQueueDequeue(DvrWriteBufferQueue* write_queue, int timeout,
DvrWriteBuffer* out_buffer, int* out_fence_fd);
-// ReadeBufferQueue
+// Overrides buffer dimension with new width and height.
+//
+// After the call successfully returns, each |dvrWriteBufferQueueDequeue| call
+// will return buffer with newly assigned |width| and |height|. When necessary,
+// old buffer will be removed from the buffer queue and replaced with new buffer
+// matching the new buffer size.
+//
+// @param write_queue The DvrWriteBufferQueue of interest.
+// @param width Desired width, cannot be Zero.
+// @param height Desired height, cannot be Zero.
+// @return Zero on success, or negative error code.
+int dvrWriteBufferQueueResizeBuffer(DvrWriteBufferQueue* write_queue,
+ uint32_t width, uint32_t height);
+
+// Destroy a read buffer queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
void dvrReadBufferQueueDestroy(DvrReadBufferQueue* read_queue);
+
+// Get the total number of buffers in a read buffer queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @return The capacity on success; or negative error code.
ssize_t dvrReadBufferQueueGetCapacity(DvrReadBufferQueue* read_queue);
+
+// Get the system unique queue id of a read buffer queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @return Queue id on success; or negative error code.
int dvrReadBufferQueueGetId(DvrReadBufferQueue* read_queue);
+
+// Create a read buffer queue from an existing read buffer queue.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @param out_read_queue The pointer of a DvrReadBufferQueue will be filled here
+// if the method call succeeds.
+// @return Zero on success, or negative error code.
int dvrReadBufferQueueCreateReadQueue(DvrReadBufferQueue* read_queue,
DvrReadBufferQueue** out_read_queue);
+
+// Dequeue a buffer to read from.
+//
+// @param read_queue The DvrReadBufferQueue of interest.
+// @param timeout Specifies the number of milliseconds that the method will
+// block. Specifying a timeout of -1 causes it to block indefinitely,
+// while specifying a timeout equal to zero cause it to return immediately,
+// even if no buffers are available.
+// @param out_buffer A targeting DvrReadBuffer object to hold the output of the
+// dequeue operation. Must be created by |dvrReadBufferCreateEmpty|.
+// @param out_fence_fd A sync fence fd defined in NDK's sync.h API, which
+// signals the release of underlying buffer. The consumer should wait until
+// this fence clears before reading data from it.
+// @param out_meta The memory area where a metadata object will be filled.
+// @param meta_size_bytes Size of the metadata object caller expects. If it
+// doesn't match the size of actually metadata transported by the buffer
+// queue, the method returns -EINVAL.
+// @return Zero on success, or negative error code.
int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
DvrReadBuffer* out_buffer, int* out_fence_fd,
void* out_meta, size_t meta_size_bytes);
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index 2426a49..8a55b20 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -7,17 +7,18 @@
#include <gtest/gtest.h>
#include "../dvr_internal.h"
+#include "../dvr_buffer_queue_internal.h"
namespace android {
namespace dvr {
namespace {
-static constexpr int kBufferWidth = 100;
-static constexpr int kBufferHeight = 1;
-static constexpr int kLayerCount = 1;
-static constexpr int kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
-static constexpr int kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
+static constexpr uint32_t kBufferWidth = 100;
+static constexpr uint32_t kBufferHeight = 1;
+static constexpr uint32_t kLayerCount = 1;
+static constexpr uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
+static constexpr uint64_t kBufferUsage = GRALLOC_USAGE_SW_READ_RARELY;
static constexpr size_t kQueueCapacity = 3;
typedef uint64_t TestMeta;
@@ -25,9 +26,14 @@
class DvrBufferQueueTest : public ::testing::Test {
protected:
void SetUp() override {
- auto config = ProducerQueueConfigBuilder().SetMetadata<TestMeta>().Build();
- write_queue_ = CreateDvrWriteBufferQueueFromProducerQueue(
- ProducerQueue::Create(config, UsagePolicy{}));
+ auto config = ProducerQueueConfigBuilder()
+ .SetDefaultWidth(kBufferWidth)
+ .SetDefaultHeight(kBufferHeight)
+ .SetDefaultFormat(kBufferFormat)
+ .SetMetadata<TestMeta>()
+ .Build();
+ write_queue_ =
+ new DvrWriteBufferQueue(ProducerQueue::Create(config, UsagePolicy{}));
ASSERT_NE(nullptr, write_queue_);
}
@@ -41,10 +47,9 @@
void AllocateBuffers(size_t buffer_count) {
size_t out_slot;
for (size_t i = 0; i < buffer_count; i++) {
- auto status =
- GetProducerQueueFromDvrWriteBufferQueue(write_queue_)
- ->AllocateBuffer(kBufferWidth, kBufferHeight, kLayerCount,
- kBufferFormat, kBufferUsage, &out_slot);
+ auto status = write_queue_->producer_queue()->AllocateBuffer(
+ kBufferWidth, kBufferHeight, kLayerCount, kBufferFormat, kBufferUsage,
+ &out_slot);
ASSERT_TRUE(status.ok());
}
}
@@ -202,9 +207,9 @@
.SetMetadata<DvrNativeBufferMetadata>()
.Build();
std::unique_ptr<DvrWriteBufferQueue, decltype(&dvrWriteBufferQueueDestroy)>
- write_queue(CreateDvrWriteBufferQueueFromProducerQueue(
- ProducerQueue::Create(config, UsagePolicy{})),
- dvrWriteBufferQueueDestroy);
+ write_queue(
+ new DvrWriteBufferQueue(ProducerQueue::Create(config, UsagePolicy{})),
+ dvrWriteBufferQueueDestroy);
ASSERT_NE(nullptr, write_queue.get());
ret = dvrWriteBufferQueueGetExternalSurface(write_queue.get(), &window);
@@ -215,6 +220,90 @@
ASSERT_TRUE(Surface::isValid(surface));
}
+// Create buffer queue of three buffers and dequeue three buffers out of it.
+// Before each dequeue operation, we resize the buffer queue and expect the
+// queue always return buffer with desired dimension.
+TEST_F(DvrBufferQueueTest, TestResizeBuffer) {
+ static constexpr int kTimeout = 0;
+ int fence_fd = -1;
+
+ DvrWriteBuffer* wb1 = nullptr;
+ DvrWriteBuffer* wb2 = nullptr;
+ DvrWriteBuffer* wb3 = nullptr;
+ AHardwareBuffer* ahb1 = nullptr;
+ AHardwareBuffer* ahb2 = nullptr;
+ AHardwareBuffer* ahb3 = nullptr;
+ AHardwareBuffer_Desc buffer_desc;
+
+ dvrWriteBufferCreateEmpty(&wb1);
+ ASSERT_NE(nullptr, wb1);
+ dvrWriteBufferCreateEmpty(&wb2);
+ ASSERT_NE(nullptr, wb2);
+ dvrWriteBufferCreateEmpty(&wb3);
+ ASSERT_NE(nullptr, wb3);
+
+ AllocateBuffers(kQueueCapacity);
+
+ // Resize before dequeuing.
+ constexpr int w1 = 10;
+ int ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w1, kBufferHeight);
+
+ // Gain first buffer for writing. All buffers will be resized.
+ ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb1, &fence_fd);
+ ASSERT_EQ(0, ret);
+ ASSERT_TRUE(dvrWriteBufferIsValid(wb1));
+ ALOGD_IF(TRACE, "TestResiveBuffer, gain buffer %p", wb1);
+ pdx::LocalHandle release_fence1(fence_fd);
+
+ // Check the buffer dimension.
+ ret = dvrWriteBufferGetAHardwareBuffer(wb1, &ahb1);
+ ASSERT_EQ(0, ret);
+ AHardwareBuffer_describe(ahb1, &buffer_desc);
+ ASSERT_EQ(w1, buffer_desc.width);
+ ASSERT_EQ(kBufferHeight, buffer_desc.height);
+ AHardwareBuffer_release(ahb1);
+
+ // Resize the queue. We are testing with blob format, keep height to be 1.
+ constexpr int w2 = 20;
+ ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w2, kBufferHeight);
+ ASSERT_EQ(0, ret);
+
+ // The next buffer we dequeued should have new width.
+ ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb2, &fence_fd);
+ ASSERT_EQ(0, ret);
+ ASSERT_TRUE(dvrWriteBufferIsValid(wb2));
+ ALOGD_IF(TRACE, "TestResiveBuffer, gain buffer %p, fence_fd=%d", wb2,
+ fence_fd);
+ pdx::LocalHandle release_fence2(fence_fd);
+
+ // Check the buffer dimension, should be new width
+ ret = dvrWriteBufferGetAHardwareBuffer(wb2, &ahb2);
+ ASSERT_EQ(0, ret);
+ AHardwareBuffer_describe(ahb2, &buffer_desc);
+ ASSERT_EQ(w2, buffer_desc.width);
+ AHardwareBuffer_release(ahb2);
+
+ // Resize the queue for the third time.
+ constexpr int w3 = 30;
+ ret = dvrWriteBufferQueueResizeBuffer(write_queue_, w3, kBufferHeight);
+ ASSERT_EQ(0, ret);
+
+ // The next buffer we dequeued should have new width.
+ ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb3, &fence_fd);
+ ASSERT_EQ(0, ret);
+ ASSERT_TRUE(dvrWriteBufferIsValid(wb3));
+ ALOGD_IF(TRACE, "TestResiveBuffer, gain buffer %p, fence_fd=%d", wb3,
+ fence_fd);
+ pdx::LocalHandle release_fence3(fence_fd);
+
+ // Check the buffer dimension, should be new width
+ ret = dvrWriteBufferGetAHardwareBuffer(wb3, &ahb3);
+ ASSERT_EQ(0, ret);
+ AHardwareBuffer_describe(ahb3, &buffer_desc);
+ ASSERT_EQ(w3, buffer_desc.width);
+ AHardwareBuffer_release(ahb3);
+}
+
} // namespace
} // namespace dvr
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index babdc0e..d836fba 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -199,16 +199,14 @@
}
Status<LocalChannelHandle> ApplicationDisplaySurface::OnCreateQueue(
- Message& /*message*/, size_t meta_size_bytes) {
+ Message& /*message*/, const ProducerQueueConfig& config) {
ATRACE_NAME("ApplicationDisplaySurface::OnCreateQueue");
ALOGD_IF(TRACE,
"ApplicationDisplaySurface::OnCreateQueue: surface_id=%d, "
"meta_size_bytes=%zu",
- surface_id(), meta_size_bytes);
+ surface_id(), config.meta_size_bytes);
std::lock_guard<std::mutex> autolock(lock_);
- auto config =
- ProducerQueueConfigBuilder().SetMetadataSize(meta_size_bytes).Build();
auto producer = ProducerQueue::Create(config, UsagePolicy{});
if (!producer) {
ALOGE(
@@ -261,19 +259,17 @@
}
Status<LocalChannelHandle> DirectDisplaySurface::OnCreateQueue(
- Message& /*message*/, size_t meta_size_bytes) {
+ Message& /*message*/, const ProducerQueueConfig& config) {
ATRACE_NAME("DirectDisplaySurface::OnCreateQueue");
ALOGD_IF(
TRACE,
"DirectDisplaySurface::OnCreateQueue: surface_id=%d meta_size_bytes=%zu",
- surface_id(), meta_size_bytes);
+ surface_id(), config.meta_size_bytes);
std::lock_guard<std::mutex> autolock(lock_);
if (!direct_queue_) {
// Inject the hw composer usage flag to enable the display to read the
// buffers.
- auto config =
- ProducerQueueConfigBuilder().SetMetadataSize(meta_size_bytes).Build();
auto producer = ProducerQueue::Create(
config, UsagePolicy{GraphicBuffer::USAGE_HW_COMPOSER, 0, 0, 0});
if (!producer) {
diff --git a/libs/vr/libvrflinger/display_surface.h b/libs/vr/libvrflinger/display_surface.h
index c456b10..5380062 100644
--- a/libs/vr/libvrflinger/display_surface.h
+++ b/libs/vr/libvrflinger/display_surface.h
@@ -66,7 +66,7 @@
}
virtual pdx::Status<pdx::LocalChannelHandle> OnCreateQueue(
- pdx::Message& message, size_t meta_size_bytes) = 0;
+ pdx::Message& message, const ProducerQueueConfig& config) = 0;
// Registers a consumer queue with the event dispatcher in DisplayService. The
// OnQueueEvent callback below is called to handle queue events.
@@ -129,7 +129,7 @@
private:
pdx::Status<pdx::LocalChannelHandle> OnCreateQueue(
- pdx::Message& message, size_t meta_size_bytes) override;
+ pdx::Message& message, const ProducerQueueConfig& config) override;
void OnQueueEvent(const std::shared_ptr<ConsumerQueue>& consumer_queue,
int events) override;
@@ -154,7 +154,7 @@
private:
pdx::Status<pdx::LocalChannelHandle> OnCreateQueue(
- pdx::Message& message, size_t meta_size_bytes) override;
+ pdx::Message& message, const ProducerQueueConfig& config) override;
void OnQueueEvent(const std::shared_ptr<ConsumerQueue>& consumer_queue,
int events) override;