/* static */
std::shared_ptr<BufferHubQueueCore> BufferHubQueueCore::Create() {
auto core = std::shared_ptr<BufferHubQueueCore>(new BufferHubQueueCore());
- core->producer_ = ProducerQueue::Create<BufferMetadata>();
+ core->producer_ = ProducerQueue::Create<NativeBufferMetadata>();
return core;
}
/* static */
std::shared_ptr<BufferHubQueueCore> BufferHubQueueCore::Create(
const std::shared_ptr<ProducerQueue>& producer) {
- if (producer->metadata_size() != sizeof(BufferMetadata)) {
+ if (producer->metadata_size() != sizeof(NativeBufferMetadata)) {
ALOGE(
"BufferHubQueueCore::Create producer's metadata size is different than "
- "the size of BufferHubQueueCore::BufferMetadata");
+ "the size of BufferHubQueueCore::NativeBufferMetadata");
return nullptr;
}
if (max_dequeued_buffers <= 0 ||
max_dequeued_buffers >
- static_cast<int>(BufferHubQueue::kMaxQueueCapacity)) {
+ static_cast<int>(BufferHubQueue::kMaxQueueCapacity -
+ BufferHubQueueCore::kDefaultUndequeuedBuffers)) {
ALOGE("setMaxDequeuedBufferCount: %d out of range (0, %zu]",
max_dequeued_buffers, BufferHubQueue::kMaxQueueCapacity);
return BAD_VALUE;
}
if (static_cast<int32_t>(core_->producer_->capacity()) <
- max_dequeued_buffer_count_) {
+ max_dequeued_buffer_count_ +
+ BufferHubQueueCore::kDefaultUndequeuedBuffers) {
// Lazy allocation. When the capacity of |core_->producer_| has not reach
// |max_dequeued_buffer_count_|, allocate new buffer.
// TODO(jwcai) To save memory, the really reasonable thing to do is to go
}
int64_t timestamp;
- int scaling_mode;
- sp<Fence> fence;
- Rect crop(Rect::EMPTY_RECT);
-
- // TODO(jwcai) The following attributes are ignored.
bool is_auto_timestamp;
- android_dataspace data_space;
+ android_dataspace dataspace;
+ Rect crop(Rect::EMPTY_RECT);
+ int scaling_mode;
uint32_t transform;
+ sp<Fence> fence;
- input.deflate(×tamp, &is_auto_timestamp, &data_space, &crop,
+ input.deflate(×tamp, &is_auto_timestamp, &dataspace, &crop,
&scaling_mode, &transform, &fence);
// Check input scaling mode is valid.
LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1);
- BufferHubQueueCore::BufferMetadata meta_data = {.timestamp = timestamp};
+ BufferHubQueueCore::NativeBufferMetadata meta_data = {};
+ meta_data.timestamp = timestamp;
+ meta_data.is_auto_timestamp = static_cast<int32_t>(is_auto_timestamp);
+ meta_data.dataspace = static_cast<int32_t>(dataspace);
+ meta_data.crop_left = crop.left;
+ meta_data.crop_top = crop.top;
+ meta_data.crop_right = crop.right;
+ meta_data.crop_bottom = crop.bottom;
+ meta_data.scaling_mode = static_cast<int32_t>(scaling_mode);
+ meta_data.transform = static_cast<int32_t>(transform);
+
buffer_producer->Post(fence_fd, &meta_data, sizeof(meta_data));
core_->buffers_[slot].mBufferState.queue();
int value = 0;
switch (what) {
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
- value = 0;
+ // TODO(b/36187402) This should be the maximum number of buffers that this
+ // producer queue's consumer can acquire. Set to be at least one. Need to
+ // find a way to set from the consumer side.
+ value = BufferHubQueueCore::kDefaultUndequeuedBuffers;
break;
case NATIVE_WINDOW_BUFFER_AGE:
value = 0;
// IGraphicBufferConsumer parity.
value = 0;
break;
- // The following queries are currently considered as unsupported.
- // TODO(jwcai) Need to carefully check the whether they should be
- // supported after all.
- case NATIVE_WINDOW_STICKY_TRANSFORM:
case NATIVE_WINDOW_DEFAULT_DATASPACE:
+ // TODO(jwcai) Return the default value android::BufferQueue is using as
+ // there is no way dvr::ConsumerQueue can set it.
+ value = 0; // HAL_DATASPACE_UNKNOWN
+ break;
+ case NATIVE_WINDOW_STICKY_TRANSFORM:
+ // TODO(jwcai) Return the default value android::BufferQueue is using as
+ // there is no way dvr::ConsumerQueue can set it.
+ value = 0;
+ break;
default:
return BAD_VALUE;
}
case NATIVE_WINDOW_API_MEDIA:
case NATIVE_WINDOW_API_CAMERA:
core_->connected_api_ = api;
- // TODO(jwcai) Fill output.
+
+ output->width = core_->producer_->default_width();
+ output->height = core_->producer_->default_height();
+
+ // default values, we don't use them yet.
+ output->transformHint = 0;
+ output->numPendingBuffers = 0;
+ output->nextFrameNumber = 0;
+ output->bufferReplaced = false;
+
break;
default:
ALOGE("BufferHubQueueProducer::connect: unknow API %d", api);
return String8("BufferHubQueue::DummyConsumer");
}
-status_t BufferHubQueueProducer::setSharedBufferMode(
- bool /* shared_buffer_mode */) {
- ALOGE("BufferHubQueueProducer::setSharedBufferMode not implemented.");
- // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow.
- return INVALID_OPERATION;
+status_t BufferHubQueueProducer::setSharedBufferMode(bool shared_buffer_mode) {
+ if (shared_buffer_mode) {
+ ALOGE("BufferHubQueueProducer::setSharedBufferMode(true) is not supported.");
+ // TODO(b/36373181) Front buffer mode for buffer hub queue as ANativeWindow.
+ return INVALID_OPERATION;
+ }
+ // Setting to default should just work as a no-op.
+ return NO_ERROR;
}
-status_t BufferHubQueueProducer::setAutoRefresh(bool /* auto_refresh */) {
- ALOGE("BufferHubQueueProducer::setAutoRefresh not implemented.");
- return INVALID_OPERATION;
+status_t BufferHubQueueProducer::setAutoRefresh(bool auto_refresh) {
+ if (auto_refresh) {
+ ALOGE("BufferHubQueueProducer::setAutoRefresh(true) is not supported.");
+ return INVALID_OPERATION;
+ }
+ // Setting to default should just work as a no-op.
+ return NO_ERROR;
}
status_t BufferHubQueueProducer::setDequeueTimeout(nsecs_t timeout) {
IBinder* BufferHubQueueProducer::onAsBinder() {
// BufferHubQueueProducer is a non-binder implementation of
// IGraphicBufferProducer.
- ALOGW("BufferHubQueueProducer::onAsBinder is not supported.");
- return nullptr;
+ ALOGW("BufferHubQueueProducer::onAsBinder is not efficiently supported.");
+ return this;
}
} // namespace dvr
// This is implemented by first detaching the buffer and then allocating a
// new buffer.
// 3. During the same epoll_wait, Consumer queue's client side gets EPOLLIN
- // event on the queue which indicates a new buffer is avaiable and the
+ // event on the queue which indicates a new buffer is available and the
// EPOLLHUP event for slot 0. Consumer handles these two events in order.
// 4. Consumer client calls BufferHubRPC::ConsumerQueueImportBuffers and both
// slot 0 and (the new) slot 1 buffer will be imported. During the import
- // of the buffer at slot 1, consuemr client detaches the old buffer so that
+ // of the buffer at slot 1, consumer client detaches the old buffer so that
// the new buffer can be registered. At the same time
// |epollhup_pending_[slot]| is marked to indicate that buffer at this slot
// was detached prior to EPOLLHUP event.
public:
static constexpr int kNoConnectedApi = -1;
+ // TODO(b/36187402) The actual implementation of BufferHubQueue's consumer
+ // side logic doesn't limit the number of buffer it can acquire
+ // simultaneously. We need a way for consumer logic to configure and enforce
+ // that.
+ static constexpr int kDefaultUndequeuedBuffers = 1;
+
// Create a BufferHubQueueCore instance by creating a new producer queue.
static std::shared_ptr<BufferHubQueueCore> Create();
- // Create a BufferHubQueueCore instance by importing an existing prodcuer queue.
+ // Create a BufferHubQueueCore instance by importing an existing prodcuer
+ // queue.
static std::shared_ptr<BufferHubQueueCore> Create(
const std::shared_ptr<ProducerQueue>& producer);
- struct BufferMetadata {
+ // The buffer metadata that an Android Surface (a.k.a. ANativeWindow)
+ // will populate. This must be aligned with the |DvrNativeBufferMetadata|
+ // defined in |dvr_buffer_queue.h|. Please do not remove, modify, or reorder
+ // existing data members. If new fields need to be added, please take extra
+ // care to make sure that new data field is padded properly the size of the
+ // struct stays same.
+ // TODO(b/37578558) Move |dvr_api.h| into a header library so that this
+ // structure won't be copied between |dvr_api.h| and |buffer_hub_qeue_core.h|.
+ struct NativeBufferMetadata {
// Timestamp of the frame.
int64_t timestamp;
+
+ // Whether the buffer is using auto timestamp.
+ int32_t is_auto_timestamp;
+
+ // Must be one of the HAL_DATASPACE_XXX value defined in system/graphics.h
+ int32_t dataspace;
+
+ // Crop extracted from an ACrop or android::Crop object.
+ int32_t crop_left;
+ int32_t crop_top;
+ int32_t crop_right;
+ int32_t crop_bottom;
+
+ // Must be one of the NATIVE_WINDOW_SCALING_MODE_XXX value defined in
+ // system/window.h.
+ int32_t scaling_mode;
+
+ // Must be one of the ANATIVEWINDOW_TRANSFORM_XXX value defined in
+ // android/native_window.h
+ int32_t transform;
+
+ // Reserved bytes for so that the struct is forward compatible.
+ int32_t reserved[16];
};
class NativeBuffer
namespace android {
namespace dvr {
-class BufferHubQueueProducer : public IGraphicBufferProducer {
+class BufferHubQueueProducer : public BnInterface<IGraphicBufferProducer> {
public:
BufferHubQueueProducer(const std::shared_ptr<BufferHubQueueCore>& core);
manager_attributes);
};
-struct VideoMeshSurfaceBufferMetadata {
- int64_t timestamp_ns;
-};
-
struct AlignmentMarker {
public:
float horizontal;
+#include "include/dvr/dvr_api.h"
#include "include/dvr/dvr_buffer_queue.h"
#include <android/native_window.h>
CHECK_PARAM(write_queue);
CHECK_PARAM(out_window);
+ if (write_queue->producer_queue_->metadata_size() !=
+ sizeof(DvrNativeBufferMetadata)) {
+ ALOGE(
+ "The size of buffer metadata (%u) of the write queue does not match of "
+ "size of DvrNativeBufferMetadata (%u).",
+ write_queue->producer_queue_->metadata_size(),
+ sizeof(DvrNativeBufferMetadata));
+ return -EINVAL;
+ }
+
// Lazy creation of |native_window_|.
if (write_queue->native_window_ == nullptr) {
std::shared_ptr<dvr::BufferHubQueueCore> core =
size_t layer_index,
size_t index);
+// The buffer metadata that an Android Surface (a.k.a. ANativeWindow)
+// will populate. A DvrWriteBufferQueue must be created with this metadata iff
+// ANativeWindow access is needed. Note that this struct must stay in sync with
+// BufferHubQueueCore::NativeBufferMetadata. Please do not remove, modify, or
+// reorder existing data members. If new fields need to be added, please take
+// extra care to make sure that new data field is padded properly the size of
+// the struct stays same.
+// TODO(b/37578558) Move |dvr_api.h| into a header library so that this structure
+// won't be copied between |dvr_api.h| and |buffer_hub_qeue_core.h|.
+struct DvrNativeBufferMetadata {
+ // Timestamp of the frame.
+ int64_t timestamp;
+
+ // Whether the buffer is using auto timestamp.
+ int32_t is_auto_timestamp;
+
+ // Must be one of the HAL_DATASPACE_XXX value defined in system/graphics.h
+ int32_t dataspace;
+
+ // Crop extracted from an ACrop or android::Crop object.
+ int32_t crop_left;
+ int32_t crop_top;
+ int32_t crop_right;
+ int32_t crop_bottom;
+
+ // Must be one of the NATIVE_WINDOW_SCALING_MODE_XXX value defined in
+ // system/window.h.
+ int32_t scaling_mode;
+
+ // Must be one of the ANATIVEWINDOW_TRANSFORM_XXX value defined in
+ // android/native_window.h
+ int32_t transform;
+
+ // Reserved bytes for so that the struct is forward compatible.
+ int32_t reserved[16];
+};
+
struct DvrApi_v1 {
// Display manager client
DvrDisplayManagerClientCreatePtr display_manager_client_create;
+#include <dvr/dvr_api.h>
#include <dvr/dvr_buffer_queue.h>
#include <gui/Surface.h>
#include <private/dvr/buffer_hub_queue_client.h>
TEST_F(DvrBufferQueueTest, TestGetExternalSurface) {
ANativeWindow* window = nullptr;
+
+ // The |write_queue_| doesn't have proper metadata (must be
+ // DvrNativeBufferMetadata) configured during creation.
int ret = dvrWriteBufferQueueGetExternalSurface(write_queue_, &window);
+ ASSERT_EQ(-EINVAL, ret);
+ ASSERT_EQ(nullptr, window);
+
+ // A write queue with DvrNativeBufferMetadata should work fine.
+ std::unique_ptr<DvrWriteBufferQueue, decltype(&dvrWriteBufferQueueDestroy)>
+ write_queue(new DvrWriteBufferQueue, dvrWriteBufferQueueDestroy);
+ write_queue->producer_queue_ =
+ ProducerQueue::Create<DvrNativeBufferMetadata>(0, 0, 0, 0);
+ ASSERT_NE(nullptr, write_queue->producer_queue_);
+ ret = dvrWriteBufferQueueGetExternalSurface(write_queue.get(), &window);
ASSERT_EQ(0, ret);
ASSERT_NE(nullptr, window);
GLuint VideoCompositor::GetActiveTextureId(EGLDisplay display) {
size_t slot;
- VideoMeshSurfaceBufferMetadata metadata;
+ BufferHubQueueCore::NativeBufferMetadata metadata;
while (true) {
// A native way to pick the active texture: always dequeue all buffers from
#include "video_mesh_surface.h"
+#include <private/dvr/buffer_hub_queue_core.h>
#include <private/dvr/display_rpc.h>
using android::pdx::LocalChannelHandle;
REPLY_ERROR_RETURN(message, EALREADY, {});
}
- auto producer = ProducerQueue::Create<VideoMeshSurfaceBufferMetadata>();
+ auto producer =
+ ProducerQueue::Create<BufferHubQueueCore::NativeBufferMetadata>();
consumer_queue_ = producer->CreateConsumerQueue();
return std::move(producer->GetChannelHandle());