Loading libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp +0 −20 Original line number Diff line number Diff line Loading @@ -50,27 +50,7 @@ status_t BufferHubQueueCore::AllocateBuffer(uint32_t width, uint32_t height, LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr, "Failed to get buffer producer at slot: %zu", slot); // Allocating a new buffer, |buffers_[slot]| should be in initial state. LOG_ALWAYS_FATAL_IF(buffers_[slot].mGraphicBuffer != nullptr, "AllocateBuffer: slot %zu is not empty.", slot); // Create new GraphicBuffer based on the newly created |buffer_producer|. Here // we have to cast |buffer_handle_t| to |native_handle_t|, it's OK because // internally, GraphicBuffer is still an |ANativeWindowBuffer| and |handle| // is still type of |buffer_handle_t| and bears const property. sp<GraphicBuffer> graphic_buffer(new GraphicBuffer( buffer_producer->width(), buffer_producer->height(), buffer_producer->format(), 1, /* layer count */ buffer_producer->usage(), buffer_producer->stride(), const_cast<native_handle_t*>(buffer_producer->buffer()->handle()), false)); LOG_ALWAYS_FATAL_IF(NO_ERROR != graphic_buffer->initCheck(), "Failed to init GraphicBuffer."); buffers_[slot].mBufferProducer = buffer_producer; buffers_[slot].mGraphicBuffer = graphic_buffer; return NO_ERROR; } Loading libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp +216 −40 Original line number Diff line number Diff line Loading @@ -8,7 +8,7 @@ namespace dvr { BufferHubQueueProducer::BufferHubQueueProducer( const std::shared_ptr<BufferHubQueueCore>& core) : core_(core), req_buffer_count_(kInvalidBufferCount) {} : core_(core) {} status_t BufferHubQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { Loading @@ -16,18 +16,48 @@ status_t BufferHubQueueProducer::requestBuffer(int slot, std::unique_lock<std::mutex> lock(core_->mutex_); if (slot < 0 || slot >= req_buffer_count_) { if (core_->connected_api_ == BufferHubQueueCore::kNoConnectedApi) { ALOGE("requestBuffer: BufferHubQueueProducer has no connected producer"); return NO_INIT; } if (slot < 0 || slot >= max_buffer_count_) { ALOGE("requestBuffer: slot index %d out of range [0, %d)", slot, req_buffer_count_); max_buffer_count_); return BAD_VALUE; } else if (!core_->buffers_[slot].mBufferState.isDequeued()) { ALOGE("requestBuffer: slot %d is not owned by the producer (state = %s)", slot, core_->buffers_[slot].mBufferState.string()); return BAD_VALUE; } else if (core_->buffers_[slot].mGraphicBuffer != nullptr) { ALOGE("requestBuffer: slot %d is not empty.", slot); return BAD_VALUE; } else if (core_->buffers_[slot].mBufferProducer == nullptr) { ALOGE("requestBuffer: slot %d is not dequeued.", slot); return BAD_VALUE; } const auto& buffer_producer = core_->buffers_[slot].mBufferProducer; // Create new GraphicBuffer based on the newly created |buffer_producer|. Here // we have to cast |buffer_handle_t| to |native_handle_t|, it's OK because // internally, GraphicBuffer is still an |ANativeWindowBuffer| and |handle| // is still type of |buffer_handle_t| and bears const property. sp<GraphicBuffer> graphic_buffer(new GraphicBuffer( buffer_producer->width(), buffer_producer->height(), buffer_producer->format(), 1, /* layer count */ buffer_producer->usage(), buffer_producer->stride(), const_cast<native_handle_t*>(buffer_producer->buffer()->handle()), false)); LOG_ALWAYS_FATAL_IF(NO_ERROR != graphic_buffer->initCheck(), "Failed to init GraphicBuffer."); core_->buffers_[slot].mGraphicBuffer = graphic_buffer; core_->buffers_[slot].mRequestBufferCalled = true; *buf = core_->buffers_[slot].mGraphicBuffer; *buf = graphic_buffer; return NO_ERROR; } Loading @@ -46,30 +76,68 @@ status_t BufferHubQueueProducer::setMaxDequeuedBufferCount( return BAD_VALUE; } req_buffer_count_ = max_dequeued_buffers; // The new dequeued_buffers count should not be violated by the number // of currently dequeued buffers. int dequeued_count = 0; for (const auto& buf : core_->buffers_) { if (buf.mBufferState.isDequeued()) { dequeued_count++; } } if (dequeued_count > max_dequeued_buffers) { ALOGE( "setMaxDequeuedBufferCount: the requested dequeued_buffers" "count (%d) exceeds the current dequeued buffer count (%d)", max_dequeued_buffers, dequeued_count); return BAD_VALUE; } max_dequeued_buffer_count_ = max_dequeued_buffers; return NO_ERROR; } status_t BufferHubQueueProducer::setAsyncMode(bool /* async */) { ALOGE("BufferHubQueueProducer::setAsyncMode not implemented."); return INVALID_OPERATION; status_t BufferHubQueueProducer::setAsyncMode(bool async) { if (async) { // TODO(b/36724099) BufferHubQueue's consumer end always acquires the buffer // automatically and behaves differently from IGraphicBufferConsumer. Thus, // android::BufferQueue's async mode (a.k.a. allocating an additional buffer // to prevent dequeueBuffer from being blocking) technically does not apply // here. // // In Daydream, non-blocking producer side dequeue is guaranteed by careful // buffer consumer implementations. In another word, BufferHubQueue based // dequeueBuffer should never block whether setAsyncMode(true) is set or // not. // // See: IGraphicBufferProducer::setAsyncMode and // BufferQueueProducer::setAsyncMode for more about original implementation. ALOGW( "BufferHubQueueProducer::setAsyncMode: BufferHubQueue should always be " "asynchronous. This call makes no effact."); return NO_ERROR; } return NO_ERROR; } status_t BufferHubQueueProducer::dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height, PixelFormat format, uint32_t usage, FrameEventHistoryDelta* /* outTimestamps */) { status_t BufferHubQueueProducer::dequeueBuffer( int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height, PixelFormat format, uint32_t usage, FrameEventHistoryDelta* /* out_timestamps */) { ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%u", width, height, format, usage); status_t ret; std::unique_lock<std::mutex> lock(core_->mutex_); if (static_cast<int32_t>(core_->producer_->capacity()) < req_buffer_count_) { if (core_->connected_api_ == BufferHubQueueCore::kNoConnectedApi) { ALOGE("dequeueBuffer: BufferQueue has no connected producer"); return NO_INIT; } if (static_cast<int32_t>(core_->producer_->capacity()) < max_dequeued_buffer_count_) { // Lazy allocation. When the capacity of |core_->producer_| has not reach // |req_buffer_count_|, allocate new buffer. // |max_dequeued_buffer_count_|, allocate new buffer. // TODO(jwcai) To save memory, the really reasonable thing to do is to go // over existing slots and find first existing one to dequeue. ret = core_->AllocateBuffer(width, height, format, usage, 1); Loading Loading @@ -126,8 +194,8 @@ status_t BufferHubQueueProducer::dequeueBuffer(int* out_slot, // BufferHubQueue). // TODO(jwcai) Clean this up, make mBufferState compatible with BufferHub's // model. LOG_ALWAYS_FATAL_IF(!core_->buffers_[slot].mBufferState.isFree() && !core_->buffers_[slot].mBufferState.isQueued(), LOG_ALWAYS_FATAL_IF((!core_->buffers_[slot].mBufferState.isFree() && !core_->buffers_[slot].mBufferState.isQueued()), "dequeueBuffer: slot %zu is not free or queued.", slot); core_->buffers_[slot].mBufferState.freeQueued(); Loading Loading @@ -170,22 +238,39 @@ status_t BufferHubQueueProducer::attachBuffer( status_t BufferHubQueueProducer::queueBuffer(int slot, const QueueBufferInput& input, QueueBufferOutput* /* output */) { QueueBufferOutput* output) { ALOGD_IF(TRACE, "queueBuffer: slot %d", slot); if (output == nullptr) { return BAD_VALUE; } 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; Rect crop(Rect::EMPTY_RECT); int scaling_mode; uint32_t transform; input.deflate(×tamp, &is_auto_timestamp, &data_space, &crop, &scaling_mode, &transform, &fence); // Check input scaling mode is valid. switch (scaling_mode) { case NATIVE_WINDOW_SCALING_MODE_FREEZE: case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: break; default: ALOGE("queueBuffer: unknown scaling mode %d", scaling_mode); return BAD_VALUE; } // Check input fence is valid. if (fence == nullptr) { ALOGE("queueBuffer: fence is NULL"); return BAD_VALUE; Loading @@ -194,25 +279,61 @@ status_t BufferHubQueueProducer::queueBuffer(int slot, status_t ret; std::unique_lock<std::mutex> lock(core_->mutex_); if (slot < 0 || slot >= req_buffer_count_) { if (core_->connected_api_ == BufferHubQueueCore::kNoConnectedApi) { ALOGE("queueBuffer: BufferQueue has no connected producer"); return NO_INIT; } if (slot < 0 || slot >= max_buffer_count_) { ALOGE("queueBuffer: slot index %d out of range [0, %d)", slot, req_buffer_count_); max_buffer_count_); return BAD_VALUE; } else if (!core_->buffers_[slot].mBufferState.isDequeued()) { ALOGE("queueBuffer: slot %d is not owned by the producer (state = %s)", slot, core_->buffers_[slot].mBufferState.string()); return BAD_VALUE; } else if ((!core_->buffers_[slot].mRequestBufferCalled || core_->buffers_[slot].mGraphicBuffer == nullptr)) { ALOGE( "queueBuffer: slot %d is not requested (mRequestBufferCalled=%d, " "mGraphicBuffer=%p)", slot, core_->buffers_[slot].mRequestBufferCalled, core_->buffers_[slot].mGraphicBuffer.get()); return BAD_VALUE; } // Post the buffer producer with timestamp in the metadata. auto buffer_producer = core_->buffers_[slot].mBufferProducer; const auto& buffer_producer = core_->buffers_[slot].mBufferProducer; // Check input crop is not out of boundary of current buffer. Rect buffer_rect(buffer_producer->width(), buffer_producer->height()); Rect cropped_rect(Rect::EMPTY_RECT); crop.intersect(buffer_rect, &cropped_rect); if (cropped_rect != crop) { ALOGE("queueBuffer: slot %d has out-of-boundary crop.", slot); return BAD_VALUE; } LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1); BufferHubQueueCore::BufferMetadata meta_data = {.timestamp = timestamp}; buffer_producer->Post(fence_fd, &meta_data, sizeof(meta_data)); core_->buffers_[slot].mBufferState.queue(); // TODO(jwcai) check how to fill in output properly. output->width = buffer_producer->width(); output->height = buffer_producer->height(); output->transformHint = 0; // default value, we don't use it yet. // |numPendingBuffers| counts of the number of buffers that has been enqueued // by the producer but not yet acquired by the consumer. Due to the nature // of BufferHubQueue design, this is hard to trace from the producer's client // side, but it's safe to assume it's zero. output->numPendingBuffers = 0; // Note that we are not setting nextFrameNumber here as it seems to be only // used by surface flinger. See more at b/22802885, ag/791760. output->nextFrameNumber = 0; return NO_ERROR; } Loading @@ -222,15 +343,20 @@ status_t BufferHubQueueProducer::cancelBuffer(int slot, std::unique_lock<std::mutex> lock(core_->mutex_); if (slot < 0 || slot >= req_buffer_count_) { if (core_->connected_api_ == BufferHubQueueCore::kNoConnectedApi) { ALOGE("cancelBuffer: BufferQueue has no connected producer"); return NO_INIT; } if (slot < 0 || slot >= max_buffer_count_) { ALOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, req_buffer_count_); max_buffer_count_); return BAD_VALUE; } else if (!core_->buffers_[slot].mBufferState.isDequeued()) { ALOGE("cancelBuffer: slot %d is not owned by the producer (state = %s)", slot, core_->buffers_[slot].mBufferState.string()); return BAD_VALUE; } else if (fence == NULL) { } else if (fence == nullptr) { ALOGE("cancelBuffer: fence is NULL"); return BAD_VALUE; } Loading @@ -249,7 +375,7 @@ status_t BufferHubQueueProducer::query(int what, int* out_value) { std::unique_lock<std::mutex> lock(core_->mutex_); if (out_value == NULL) { if (out_value == nullptr) { ALOGE("query: out_value was NULL"); return BAD_VALUE; } Loading @@ -262,15 +388,30 @@ status_t BufferHubQueueProducer::query(int what, int* out_value) { case NATIVE_WINDOW_BUFFER_AGE: 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_WIDTH: value = core_->producer_->default_width(); break; case NATIVE_WINDOW_HEIGHT: value = core_->producer_->default_height(); break; case NATIVE_WINDOW_FORMAT: case NATIVE_WINDOW_STICKY_TRANSFORM: value = core_->producer_->default_format(); break; case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: // BufferHubQueue is always operating in async mode, thus semantically // consumer can never be running behind. See BufferQueueCore.cpp core // for more information about the original meaning of this flag. value = 0; break; case NATIVE_WINDOW_CONSUMER_USAGE_BITS: // TODO(jwcai) This is currently not implement as we don't need // 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: default: return BAD_VALUE; Loading @@ -282,24 +423,58 @@ status_t BufferHubQueueProducer::query(int what, int* out_value) { } status_t BufferHubQueueProducer::connect( const sp<IProducerListener>& /* listener */, int /* api */, bool /* producer_controlled_by_app */, QueueBufferOutput* /* output */) { const sp<IProducerListener>& /* listener */, int api, bool /* producer_controlled_by_app */, QueueBufferOutput* output) { // Consumer interaction are actually handled by buffer hub, and we need // to maintain consumer operations here. Hence |connect| is a NO-OP. // to maintain consumer operations here. We only need to perform basic input // parameter checks here. ALOGD_IF(TRACE, __FUNCTION__); if (output == nullptr) { return BAD_VALUE; } std::unique_lock<std::mutex> lock(core_->mutex_); if (core_->connected_api_ != BufferHubQueueCore::kNoConnectedApi) { return BAD_VALUE; } switch (api) { case NATIVE_WINDOW_API_EGL: case NATIVE_WINDOW_API_CPU: case NATIVE_WINDOW_API_MEDIA: case NATIVE_WINDOW_API_CAMERA: core_->connected_api_ = api; // TODO(jwcai) Fill output. break; default: ALOGE("BufferHubQueueProducer::connect: unknow API %d", api); return BAD_VALUE; } return NO_ERROR; } status_t BufferHubQueueProducer::disconnect(int /* api */, DisconnectMode /* mode */) { status_t BufferHubQueueProducer::disconnect(int api, DisconnectMode mode) { // Consumer interaction are actually handled by buffer hub, and we need // to maintain consumer operations here. Hence |disconnect| is a NO-OP. // to maintain consumer operations here. We only need to perform basic input // parameter checks here. ALOGD_IF(TRACE, __FUNCTION__); std::unique_lock<std::mutex> lock(core_->mutex_); if (api != core_->connected_api_) { return BAD_VALUE; } core_->connected_api_ = BufferHubQueueCore::kNoConnectedApi; return NO_ERROR; } status_t BufferHubQueueProducer::setSidebandStream( const sp<NativeHandle>& stream) { if (stream != NULL) { if (stream != nullptr) { // TODO(jwcai) Investigate how is is used, maybe use BufferHubBuffer's // metadata. ALOGE("SidebandStream is not currently supported."); Loading @@ -314,7 +489,7 @@ void BufferHubQueueProducer::allocateBuffers(uint32_t /* width */, uint32_t /* usage */) { // TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number // of buffers permitted by the current BufferQueue configuration (aka // |req_buffer_count_|). // |max_buffer_count_|). ALOGE("BufferHubQueueProducer::allocateBuffers not implemented."); } Loading Loading @@ -343,6 +518,7 @@ String8 BufferHubQueueProducer::getConsumerName() const { 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; } Loading libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h +21 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,15 @@ class BufferHubQueue : public pdx::Client { // a new consumer queue client or nullptr on failure. std::unique_ptr<ConsumerQueue> CreateConsumerQueue(); // Return the default buffer width of this buffer queue. size_t default_width() const { return default_width_; } // Return the default buffer height of this buffer queue. size_t default_height() const { return default_height_; } // Return the default buffer format of this buffer queue. int32_t default_format() const { return default_format_; } // Return the number of buffers avaiable for dequeue. size_t count() const { return available_buffers_.GetSize(); } Loading Loading @@ -169,6 +178,18 @@ class BufferHubQueue : public pdx::Client { void operator=(BufferInfo&) = delete; }; // Default buffer width that can be set to override the buffer width when a // width and height of 0 are specified in AllocateBuffer. size_t default_width_{1}; // Default buffer height that can be set to override the buffer height when a // width and height of 0 are specified in AllocateBuffer. size_t default_height_{1}; // Default buffer format that can be set to override the buffer format when it // isn't specified in AllocateBuffer. int32_t default_format_{PIXEL_FORMAT_RGBA_8888}; // Buffer queue: // |buffers_| tracks all |BufferHubBuffer|s created by this |BufferHubQueue|. std::vector<std::shared_ptr<BufferHubBuffer>> buffers_; Loading libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_core.h +5 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ class BufferHubQueueCore { friend class BufferHubQueueProducer; public: static constexpr int kNoConnectedApi = -1; // Create a BufferHubQueueCore instance by creating a new producer queue. static std::shared_ptr<BufferHubQueueCore> Create(); Loading Loading @@ -87,6 +89,9 @@ class BufferHubQueueCore { // Mutex for thread safety. std::mutex mutex_; // Connect client API, should be one of the NATIVE_WINDOW_API_* flags. int connected_api_{kNoConnectedApi}; // |buffers_| stores the buffers that have been dequeued from // |dvr::BufferHubQueue|, It is initialized to invalid buffers, and gets // filled in with the result of |Dequeue|. Loading libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h +6 −4 Original line number Diff line number Diff line Loading @@ -103,13 +103,15 @@ class BufferHubQueueProducer : public IGraphicBufferProducer { private: using LocalHandle = pdx::LocalHandle; static constexpr int kInvalidBufferCount = -1; // |core_| holds the actually buffer slots. std::shared_ptr<BufferHubQueueCore> core_; // |req_buffer_count_| sets the capacity of the underlying buffer queue. int32_t req_buffer_count_; // |max_buffer_count_| sets the capacity of the underlying buffer queue. int32_t max_buffer_count_{BufferHubQueue::kMaxQueueCapacity}; // |max_dequeued_buffer_count_| set the maximum number of buffers that can // be dequeued at the same momment. int32_t max_dequeued_buffer_count_{1}; }; } // namespace dvr Loading Loading
libs/vr/libbufferhubqueue/buffer_hub_queue_core.cpp +0 −20 Original line number Diff line number Diff line Loading @@ -50,27 +50,7 @@ status_t BufferHubQueueCore::AllocateBuffer(uint32_t width, uint32_t height, LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr, "Failed to get buffer producer at slot: %zu", slot); // Allocating a new buffer, |buffers_[slot]| should be in initial state. LOG_ALWAYS_FATAL_IF(buffers_[slot].mGraphicBuffer != nullptr, "AllocateBuffer: slot %zu is not empty.", slot); // Create new GraphicBuffer based on the newly created |buffer_producer|. Here // we have to cast |buffer_handle_t| to |native_handle_t|, it's OK because // internally, GraphicBuffer is still an |ANativeWindowBuffer| and |handle| // is still type of |buffer_handle_t| and bears const property. sp<GraphicBuffer> graphic_buffer(new GraphicBuffer( buffer_producer->width(), buffer_producer->height(), buffer_producer->format(), 1, /* layer count */ buffer_producer->usage(), buffer_producer->stride(), const_cast<native_handle_t*>(buffer_producer->buffer()->handle()), false)); LOG_ALWAYS_FATAL_IF(NO_ERROR != graphic_buffer->initCheck(), "Failed to init GraphicBuffer."); buffers_[slot].mBufferProducer = buffer_producer; buffers_[slot].mGraphicBuffer = graphic_buffer; return NO_ERROR; } Loading
libs/vr/libbufferhubqueue/buffer_hub_queue_producer.cpp +216 −40 Original line number Diff line number Diff line Loading @@ -8,7 +8,7 @@ namespace dvr { BufferHubQueueProducer::BufferHubQueueProducer( const std::shared_ptr<BufferHubQueueCore>& core) : core_(core), req_buffer_count_(kInvalidBufferCount) {} : core_(core) {} status_t BufferHubQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { Loading @@ -16,18 +16,48 @@ status_t BufferHubQueueProducer::requestBuffer(int slot, std::unique_lock<std::mutex> lock(core_->mutex_); if (slot < 0 || slot >= req_buffer_count_) { if (core_->connected_api_ == BufferHubQueueCore::kNoConnectedApi) { ALOGE("requestBuffer: BufferHubQueueProducer has no connected producer"); return NO_INIT; } if (slot < 0 || slot >= max_buffer_count_) { ALOGE("requestBuffer: slot index %d out of range [0, %d)", slot, req_buffer_count_); max_buffer_count_); return BAD_VALUE; } else if (!core_->buffers_[slot].mBufferState.isDequeued()) { ALOGE("requestBuffer: slot %d is not owned by the producer (state = %s)", slot, core_->buffers_[slot].mBufferState.string()); return BAD_VALUE; } else if (core_->buffers_[slot].mGraphicBuffer != nullptr) { ALOGE("requestBuffer: slot %d is not empty.", slot); return BAD_VALUE; } else if (core_->buffers_[slot].mBufferProducer == nullptr) { ALOGE("requestBuffer: slot %d is not dequeued.", slot); return BAD_VALUE; } const auto& buffer_producer = core_->buffers_[slot].mBufferProducer; // Create new GraphicBuffer based on the newly created |buffer_producer|. Here // we have to cast |buffer_handle_t| to |native_handle_t|, it's OK because // internally, GraphicBuffer is still an |ANativeWindowBuffer| and |handle| // is still type of |buffer_handle_t| and bears const property. sp<GraphicBuffer> graphic_buffer(new GraphicBuffer( buffer_producer->width(), buffer_producer->height(), buffer_producer->format(), 1, /* layer count */ buffer_producer->usage(), buffer_producer->stride(), const_cast<native_handle_t*>(buffer_producer->buffer()->handle()), false)); LOG_ALWAYS_FATAL_IF(NO_ERROR != graphic_buffer->initCheck(), "Failed to init GraphicBuffer."); core_->buffers_[slot].mGraphicBuffer = graphic_buffer; core_->buffers_[slot].mRequestBufferCalled = true; *buf = core_->buffers_[slot].mGraphicBuffer; *buf = graphic_buffer; return NO_ERROR; } Loading @@ -46,30 +76,68 @@ status_t BufferHubQueueProducer::setMaxDequeuedBufferCount( return BAD_VALUE; } req_buffer_count_ = max_dequeued_buffers; // The new dequeued_buffers count should not be violated by the number // of currently dequeued buffers. int dequeued_count = 0; for (const auto& buf : core_->buffers_) { if (buf.mBufferState.isDequeued()) { dequeued_count++; } } if (dequeued_count > max_dequeued_buffers) { ALOGE( "setMaxDequeuedBufferCount: the requested dequeued_buffers" "count (%d) exceeds the current dequeued buffer count (%d)", max_dequeued_buffers, dequeued_count); return BAD_VALUE; } max_dequeued_buffer_count_ = max_dequeued_buffers; return NO_ERROR; } status_t BufferHubQueueProducer::setAsyncMode(bool /* async */) { ALOGE("BufferHubQueueProducer::setAsyncMode not implemented."); return INVALID_OPERATION; status_t BufferHubQueueProducer::setAsyncMode(bool async) { if (async) { // TODO(b/36724099) BufferHubQueue's consumer end always acquires the buffer // automatically and behaves differently from IGraphicBufferConsumer. Thus, // android::BufferQueue's async mode (a.k.a. allocating an additional buffer // to prevent dequeueBuffer from being blocking) technically does not apply // here. // // In Daydream, non-blocking producer side dequeue is guaranteed by careful // buffer consumer implementations. In another word, BufferHubQueue based // dequeueBuffer should never block whether setAsyncMode(true) is set or // not. // // See: IGraphicBufferProducer::setAsyncMode and // BufferQueueProducer::setAsyncMode for more about original implementation. ALOGW( "BufferHubQueueProducer::setAsyncMode: BufferHubQueue should always be " "asynchronous. This call makes no effact."); return NO_ERROR; } return NO_ERROR; } status_t BufferHubQueueProducer::dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height, PixelFormat format, uint32_t usage, FrameEventHistoryDelta* /* outTimestamps */) { status_t BufferHubQueueProducer::dequeueBuffer( int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height, PixelFormat format, uint32_t usage, FrameEventHistoryDelta* /* out_timestamps */) { ALOGD_IF(TRACE, "dequeueBuffer: w=%u, h=%u, format=%d, usage=%u", width, height, format, usage); status_t ret; std::unique_lock<std::mutex> lock(core_->mutex_); if (static_cast<int32_t>(core_->producer_->capacity()) < req_buffer_count_) { if (core_->connected_api_ == BufferHubQueueCore::kNoConnectedApi) { ALOGE("dequeueBuffer: BufferQueue has no connected producer"); return NO_INIT; } if (static_cast<int32_t>(core_->producer_->capacity()) < max_dequeued_buffer_count_) { // Lazy allocation. When the capacity of |core_->producer_| has not reach // |req_buffer_count_|, allocate new buffer. // |max_dequeued_buffer_count_|, allocate new buffer. // TODO(jwcai) To save memory, the really reasonable thing to do is to go // over existing slots and find first existing one to dequeue. ret = core_->AllocateBuffer(width, height, format, usage, 1); Loading Loading @@ -126,8 +194,8 @@ status_t BufferHubQueueProducer::dequeueBuffer(int* out_slot, // BufferHubQueue). // TODO(jwcai) Clean this up, make mBufferState compatible with BufferHub's // model. LOG_ALWAYS_FATAL_IF(!core_->buffers_[slot].mBufferState.isFree() && !core_->buffers_[slot].mBufferState.isQueued(), LOG_ALWAYS_FATAL_IF((!core_->buffers_[slot].mBufferState.isFree() && !core_->buffers_[slot].mBufferState.isQueued()), "dequeueBuffer: slot %zu is not free or queued.", slot); core_->buffers_[slot].mBufferState.freeQueued(); Loading Loading @@ -170,22 +238,39 @@ status_t BufferHubQueueProducer::attachBuffer( status_t BufferHubQueueProducer::queueBuffer(int slot, const QueueBufferInput& input, QueueBufferOutput* /* output */) { QueueBufferOutput* output) { ALOGD_IF(TRACE, "queueBuffer: slot %d", slot); if (output == nullptr) { return BAD_VALUE; } 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; Rect crop(Rect::EMPTY_RECT); int scaling_mode; uint32_t transform; input.deflate(×tamp, &is_auto_timestamp, &data_space, &crop, &scaling_mode, &transform, &fence); // Check input scaling mode is valid. switch (scaling_mode) { case NATIVE_WINDOW_SCALING_MODE_FREEZE: case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: break; default: ALOGE("queueBuffer: unknown scaling mode %d", scaling_mode); return BAD_VALUE; } // Check input fence is valid. if (fence == nullptr) { ALOGE("queueBuffer: fence is NULL"); return BAD_VALUE; Loading @@ -194,25 +279,61 @@ status_t BufferHubQueueProducer::queueBuffer(int slot, status_t ret; std::unique_lock<std::mutex> lock(core_->mutex_); if (slot < 0 || slot >= req_buffer_count_) { if (core_->connected_api_ == BufferHubQueueCore::kNoConnectedApi) { ALOGE("queueBuffer: BufferQueue has no connected producer"); return NO_INIT; } if (slot < 0 || slot >= max_buffer_count_) { ALOGE("queueBuffer: slot index %d out of range [0, %d)", slot, req_buffer_count_); max_buffer_count_); return BAD_VALUE; } else if (!core_->buffers_[slot].mBufferState.isDequeued()) { ALOGE("queueBuffer: slot %d is not owned by the producer (state = %s)", slot, core_->buffers_[slot].mBufferState.string()); return BAD_VALUE; } else if ((!core_->buffers_[slot].mRequestBufferCalled || core_->buffers_[slot].mGraphicBuffer == nullptr)) { ALOGE( "queueBuffer: slot %d is not requested (mRequestBufferCalled=%d, " "mGraphicBuffer=%p)", slot, core_->buffers_[slot].mRequestBufferCalled, core_->buffers_[slot].mGraphicBuffer.get()); return BAD_VALUE; } // Post the buffer producer with timestamp in the metadata. auto buffer_producer = core_->buffers_[slot].mBufferProducer; const auto& buffer_producer = core_->buffers_[slot].mBufferProducer; // Check input crop is not out of boundary of current buffer. Rect buffer_rect(buffer_producer->width(), buffer_producer->height()); Rect cropped_rect(Rect::EMPTY_RECT); crop.intersect(buffer_rect, &cropped_rect); if (cropped_rect != crop) { ALOGE("queueBuffer: slot %d has out-of-boundary crop.", slot); return BAD_VALUE; } LocalHandle fence_fd(fence->isValid() ? fence->dup() : -1); BufferHubQueueCore::BufferMetadata meta_data = {.timestamp = timestamp}; buffer_producer->Post(fence_fd, &meta_data, sizeof(meta_data)); core_->buffers_[slot].mBufferState.queue(); // TODO(jwcai) check how to fill in output properly. output->width = buffer_producer->width(); output->height = buffer_producer->height(); output->transformHint = 0; // default value, we don't use it yet. // |numPendingBuffers| counts of the number of buffers that has been enqueued // by the producer but not yet acquired by the consumer. Due to the nature // of BufferHubQueue design, this is hard to trace from the producer's client // side, but it's safe to assume it's zero. output->numPendingBuffers = 0; // Note that we are not setting nextFrameNumber here as it seems to be only // used by surface flinger. See more at b/22802885, ag/791760. output->nextFrameNumber = 0; return NO_ERROR; } Loading @@ -222,15 +343,20 @@ status_t BufferHubQueueProducer::cancelBuffer(int slot, std::unique_lock<std::mutex> lock(core_->mutex_); if (slot < 0 || slot >= req_buffer_count_) { if (core_->connected_api_ == BufferHubQueueCore::kNoConnectedApi) { ALOGE("cancelBuffer: BufferQueue has no connected producer"); return NO_INIT; } if (slot < 0 || slot >= max_buffer_count_) { ALOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, req_buffer_count_); max_buffer_count_); return BAD_VALUE; } else if (!core_->buffers_[slot].mBufferState.isDequeued()) { ALOGE("cancelBuffer: slot %d is not owned by the producer (state = %s)", slot, core_->buffers_[slot].mBufferState.string()); return BAD_VALUE; } else if (fence == NULL) { } else if (fence == nullptr) { ALOGE("cancelBuffer: fence is NULL"); return BAD_VALUE; } Loading @@ -249,7 +375,7 @@ status_t BufferHubQueueProducer::query(int what, int* out_value) { std::unique_lock<std::mutex> lock(core_->mutex_); if (out_value == NULL) { if (out_value == nullptr) { ALOGE("query: out_value was NULL"); return BAD_VALUE; } Loading @@ -262,15 +388,30 @@ status_t BufferHubQueueProducer::query(int what, int* out_value) { case NATIVE_WINDOW_BUFFER_AGE: 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_WIDTH: value = core_->producer_->default_width(); break; case NATIVE_WINDOW_HEIGHT: value = core_->producer_->default_height(); break; case NATIVE_WINDOW_FORMAT: case NATIVE_WINDOW_STICKY_TRANSFORM: value = core_->producer_->default_format(); break; case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: // BufferHubQueue is always operating in async mode, thus semantically // consumer can never be running behind. See BufferQueueCore.cpp core // for more information about the original meaning of this flag. value = 0; break; case NATIVE_WINDOW_CONSUMER_USAGE_BITS: // TODO(jwcai) This is currently not implement as we don't need // 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: default: return BAD_VALUE; Loading @@ -282,24 +423,58 @@ status_t BufferHubQueueProducer::query(int what, int* out_value) { } status_t BufferHubQueueProducer::connect( const sp<IProducerListener>& /* listener */, int /* api */, bool /* producer_controlled_by_app */, QueueBufferOutput* /* output */) { const sp<IProducerListener>& /* listener */, int api, bool /* producer_controlled_by_app */, QueueBufferOutput* output) { // Consumer interaction are actually handled by buffer hub, and we need // to maintain consumer operations here. Hence |connect| is a NO-OP. // to maintain consumer operations here. We only need to perform basic input // parameter checks here. ALOGD_IF(TRACE, __FUNCTION__); if (output == nullptr) { return BAD_VALUE; } std::unique_lock<std::mutex> lock(core_->mutex_); if (core_->connected_api_ != BufferHubQueueCore::kNoConnectedApi) { return BAD_VALUE; } switch (api) { case NATIVE_WINDOW_API_EGL: case NATIVE_WINDOW_API_CPU: case NATIVE_WINDOW_API_MEDIA: case NATIVE_WINDOW_API_CAMERA: core_->connected_api_ = api; // TODO(jwcai) Fill output. break; default: ALOGE("BufferHubQueueProducer::connect: unknow API %d", api); return BAD_VALUE; } return NO_ERROR; } status_t BufferHubQueueProducer::disconnect(int /* api */, DisconnectMode /* mode */) { status_t BufferHubQueueProducer::disconnect(int api, DisconnectMode mode) { // Consumer interaction are actually handled by buffer hub, and we need // to maintain consumer operations here. Hence |disconnect| is a NO-OP. // to maintain consumer operations here. We only need to perform basic input // parameter checks here. ALOGD_IF(TRACE, __FUNCTION__); std::unique_lock<std::mutex> lock(core_->mutex_); if (api != core_->connected_api_) { return BAD_VALUE; } core_->connected_api_ = BufferHubQueueCore::kNoConnectedApi; return NO_ERROR; } status_t BufferHubQueueProducer::setSidebandStream( const sp<NativeHandle>& stream) { if (stream != NULL) { if (stream != nullptr) { // TODO(jwcai) Investigate how is is used, maybe use BufferHubBuffer's // metadata. ALOGE("SidebandStream is not currently supported."); Loading @@ -314,7 +489,7 @@ void BufferHubQueueProducer::allocateBuffers(uint32_t /* width */, uint32_t /* usage */) { // TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number // of buffers permitted by the current BufferQueue configuration (aka // |req_buffer_count_|). // |max_buffer_count_|). ALOGE("BufferHubQueueProducer::allocateBuffers not implemented."); } Loading Loading @@ -343,6 +518,7 @@ String8 BufferHubQueueProducer::getConsumerName() const { 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; } Loading
libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h +21 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,15 @@ class BufferHubQueue : public pdx::Client { // a new consumer queue client or nullptr on failure. std::unique_ptr<ConsumerQueue> CreateConsumerQueue(); // Return the default buffer width of this buffer queue. size_t default_width() const { return default_width_; } // Return the default buffer height of this buffer queue. size_t default_height() const { return default_height_; } // Return the default buffer format of this buffer queue. int32_t default_format() const { return default_format_; } // Return the number of buffers avaiable for dequeue. size_t count() const { return available_buffers_.GetSize(); } Loading Loading @@ -169,6 +178,18 @@ class BufferHubQueue : public pdx::Client { void operator=(BufferInfo&) = delete; }; // Default buffer width that can be set to override the buffer width when a // width and height of 0 are specified in AllocateBuffer. size_t default_width_{1}; // Default buffer height that can be set to override the buffer height when a // width and height of 0 are specified in AllocateBuffer. size_t default_height_{1}; // Default buffer format that can be set to override the buffer format when it // isn't specified in AllocateBuffer. int32_t default_format_{PIXEL_FORMAT_RGBA_8888}; // Buffer queue: // |buffers_| tracks all |BufferHubBuffer|s created by this |BufferHubQueue|. std::vector<std::shared_ptr<BufferHubBuffer>> buffers_; Loading
libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_core.h +5 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ class BufferHubQueueCore { friend class BufferHubQueueProducer; public: static constexpr int kNoConnectedApi = -1; // Create a BufferHubQueueCore instance by creating a new producer queue. static std::shared_ptr<BufferHubQueueCore> Create(); Loading Loading @@ -87,6 +89,9 @@ class BufferHubQueueCore { // Mutex for thread safety. std::mutex mutex_; // Connect client API, should be one of the NATIVE_WINDOW_API_* flags. int connected_api_{kNoConnectedApi}; // |buffers_| stores the buffers that have been dequeued from // |dvr::BufferHubQueue|, It is initialized to invalid buffers, and gets // filled in with the result of |Dequeue|. Loading
libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_producer.h +6 −4 Original line number Diff line number Diff line Loading @@ -103,13 +103,15 @@ class BufferHubQueueProducer : public IGraphicBufferProducer { private: using LocalHandle = pdx::LocalHandle; static constexpr int kInvalidBufferCount = -1; // |core_| holds the actually buffer slots. std::shared_ptr<BufferHubQueueCore> core_; // |req_buffer_count_| sets the capacity of the underlying buffer queue. int32_t req_buffer_count_; // |max_buffer_count_| sets the capacity of the underlying buffer queue. int32_t max_buffer_count_{BufferHubQueue::kMaxQueueCapacity}; // |max_dequeued_buffer_count_| set the maximum number of buffers that can // be dequeued at the same momment. int32_t max_dequeued_buffer_count_{1}; }; } // namespace dvr Loading