SetupQueue(status.get());
}
-Status<void> ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height,
- uint32_t layer_count,
- uint32_t format, uint64_t usage,
- size_t* out_slot) {
- if (out_slot == nullptr) {
- ALOGE("ProducerQueue::AllocateBuffer: Parameter out_slot cannot be null.");
- return ErrorStatus(EINVAL);
- }
-
- if (is_full()) {
- ALOGE("ProducerQueue::AllocateBuffer queue is at maximum capacity: %zu",
- capacity());
+Status<std::vector<size_t>> ProducerQueue::AllocateBuffers(
+ uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
+ uint64_t usage, size_t buffer_count) {
+ if (capacity() + buffer_count > kMaxQueueCapacity) {
+ ALOGE(
+ "ProducerQueue::AllocateBuffers: queue is at capacity: %zu, cannot "
+ "allocate %zu more buffer(s).",
+ capacity(), buffer_count);
return ErrorStatus(E2BIG);
}
- const size_t kBufferCount = 1u;
Status<std::vector<std::pair<LocalChannelHandle, size_t>>> status =
InvokeRemoteMethod<BufferHubRPC::ProducerQueueAllocateBuffers>(
- width, height, layer_count, format, usage, kBufferCount);
+ width, height, layer_count, format, usage, buffer_count);
if (!status) {
- ALOGE("ProducerQueue::AllocateBuffer failed to create producer buffer: %s",
+ ALOGE("ProducerQueue::AllocateBuffers: failed to allocate buffers: %s",
status.GetErrorMessage().c_str());
return status.error_status();
}
auto buffer_handle_slots = status.take();
- LOG_ALWAYS_FATAL_IF(buffer_handle_slots.size() != kBufferCount,
+ LOG_ALWAYS_FATAL_IF(buffer_handle_slots.size() != buffer_count,
"BufferHubRPC::ProducerQueueAllocateBuffers should "
- "return one and only one buffer handle.");
+ "return %zu buffer handle(s), but returned %zu instead.",
+ buffer_count, buffer_handle_slots.size());
+
+ std::vector<size_t> buffer_slots;
+ buffer_slots.reserve(buffer_count);
+
+ // Bookkeeping for each buffer.
+ for (auto& hs : buffer_handle_slots) {
+ auto& buffer_handle = hs.first;
+ size_t buffer_slot = hs.second;
+
+ // Note that import might (though very unlikely) fail. If so, buffer_handle
+ // will be closed and included in returned buffer_slots.
+ if (AddBuffer(BufferProducer::Import(std::move(buffer_handle)),
+ buffer_slot)) {
+ ALOGD_IF(TRACE, "ProducerQueue::AllocateBuffers: new buffer at slot: %zu",
+ buffer_slot);
+ buffer_slots.push_back(buffer_slot);
+ }
+ }
+ if (buffer_slots.size() == 0) {
+ // Error out if no buffer is allocated and improted.
+ ALOGE(TRACE, "ProducerQueue::AllocateBuffers: no buffer allocated.");
+ ErrorStatus(ENOMEM);
+ }
+
+ return {std::move(buffer_slots)};
+}
+
+Status<size_t> ProducerQueue::AllocateBuffer(uint32_t width, uint32_t height,
+ uint32_t layer_count,
+ uint32_t format, uint64_t usage) {
// We only allocate one buffer at a time.
- auto& buffer_handle = buffer_handle_slots[0].first;
- size_t buffer_slot = buffer_handle_slots[0].second;
- ALOGD_IF(TRACE,
- "ProducerQueue::AllocateBuffer, new buffer, channel_handle: %d",
- buffer_handle.value());
+ constexpr size_t buffer_count = 1;
+ auto status =
+ AllocateBuffers(width, height, layer_count, format, usage, buffer_count);
+ if (!status) {
+ ALOGE("ProducerQueue::AllocateBuffer: Failed to allocate buffer: %s",
+ status.GetErrorMessage().c_str());
+ return status.error_status();
+ }
+
+ if (status.get().size() == 0) {
+ ALOGE(TRACE, "ProducerQueue::AllocateBuffer: no buffer allocated.");
+ ErrorStatus(ENOMEM);
+ }
- *out_slot = buffer_slot;
- return AddBuffer(BufferProducer::Import(std::move(buffer_handle)),
- buffer_slot);
+ return {status.get()[0]};
}
Status<void> ProducerQueue::AddBuffer(
uint32_t layer_count,
PixelFormat format,
uint64_t usage) {
- size_t slot;
auto status =
- queue_->AllocateBuffer(width, height, layer_count, format, usage, &slot);
+ queue_->AllocateBuffer(width, height, layer_count, format, usage);
if (!status) {
ALOGE(
"BufferHubQueueProducer::AllocateBuffer: Failed to allocate buffer: %s",
return NO_MEMORY;
}
+ size_t slot = status.get();
auto buffer_producer = queue_->GetBuffer(slot);
LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr,
BufferHubQueue::GetBuffer(slot));
}
+ // Batch allocate buffers. Once allocated, producer buffers are automatically
+ // enqueue'd into the ProducerQueue and available to use (i.e. in GAINED
+ // state). Upon success, returns a list of slots for each buffer allocated.
+ pdx::Status<std::vector<size_t>> AllocateBuffers(
+ uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
+ uint64_t usage, size_t buffer_count);
+
// Allocate producer buffer to populate the queue. Once allocated, a producer
// buffer is automatically enqueue'd into the ProducerQueue and available to
- // use (i.e. in GAINED state).
- pdx::Status<void> AllocateBuffer(uint32_t width, uint32_t height,
- uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t* out_slot);
+ // use (i.e. in GAINED state). Upon success, returns the slot number for the
+ // buffer allocated.
+ pdx::Status<size_t> AllocateBuffer(uint32_t width, uint32_t height,
+ uint32_t layer_count, uint32_t format,
+ uint64_t usage);
// Add a producer buffer to populate the queue. Once added, a producer buffer
// is available to use (i.e. in GAINED state).
void AllocateBuffer(size_t* slot_out = nullptr) {
// Create producer buffer.
- size_t slot;
auto status = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage, &slot);
- ASSERT_TRUE(status.ok());
+ kBufferUsage);
+ ASSERT_TRUE(status.ok());
+ size_t slot = status.take();
if (slot_out)
*slot_out = slot;
}
UsagePolicy{set_mask, 0, 0, 0}));
// When allocation, leave out |set_mask| from usage bits on purpose.
- size_t slot;
auto status = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage & ~set_mask, &slot);
+ kBufferUsage & ~set_mask);
ASSERT_TRUE(status.ok());
LocalHandle fence;
+ size_t slot;
auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
UsagePolicy{0, clear_mask, 0, 0}));
// When allocation, add |clear_mask| into usage bits on purpose.
- size_t slot;
auto status = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage | clear_mask, &slot);
+ kBufferUsage | clear_mask);
ASSERT_TRUE(status.ok());
LocalHandle fence;
+ size_t slot;
auto p1_status = producer_queue_->Dequeue(0, &slot, &fence);
ASSERT_TRUE(p1_status.ok());
auto p1 = p1_status.take();
// Now that |deny_set_mask| is illegal, allocation without those bits should
// be able to succeed.
- size_t slot;
auto status = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage & ~deny_set_mask, &slot);
+ kBufferUsage & ~deny_set_mask);
ASSERT_TRUE(status.ok());
// While allocation with those bits should fail.
status = producer_queue_->AllocateBuffer(kBufferWidth, kBufferHeight,
kBufferLayerCount, kBufferFormat,
- kBufferUsage | deny_set_mask, &slot);
+ kBufferUsage | deny_set_mask);
ASSERT_FALSE(status.ok());
ASSERT_EQ(EINVAL, status.error());
}
// Now that clearing |deny_clear_mask| is illegal (i.e. setting these bits are
// mandatory), allocation with those bits should be able to succeed.
- size_t slot;
auto status = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage | deny_clear_mask, &slot);
+ kBufferUsage | deny_clear_mask);
ASSERT_TRUE(status.ok());
// While allocation without those bits should fail.
status = producer_queue_->AllocateBuffer(
kBufferWidth, kBufferHeight, kBufferLayerCount, kBufferFormat,
- kBufferUsage & ~deny_clear_mask, &slot);
+ kBufferUsage & ~deny_clear_mask);
ASSERT_FALSE(status.ok());
ASSERT_EQ(EINVAL, status.error());
}
auto producer_queue = status.take();
ALOGD_IF(TRACE, "Surface::CreateQueue: Allocating %zu buffers...", capacity);
- for (size_t i = 0; i < capacity; i++) {
- size_t slot;
- auto allocate_status = producer_queue->AllocateBuffer(
- width, height, layer_count, format, usage, &slot);
- if (!allocate_status) {
- ALOGE(
- "Surface::CreateQueue: Failed to allocate buffer on queue_id=%d: %s",
+ auto allocate_status = producer_queue->AllocateBuffers(
+ width, height, layer_count, format, usage, capacity);
+ if (!allocate_status) {
+ ALOGE("Surface::CreateQueue: Failed to allocate buffer on queue_id=%d: %s",
producer_queue->id(), allocate_status.GetErrorMessage().c_str());
- return allocate_status.error_status();
- }
- ALOGD_IF(
- TRACE,
- "Surface::CreateQueue: Allocated buffer at slot=%zu of capacity=%zu",
- slot, capacity);
+ return allocate_status.error_status();
}
return {std::move(producer_queue)};
}
auto allocate_status = producer_queue_->AllocateBuffer(
- width_, height_, old_layer_count, format_, old_usage, &slot);
+ width_, height_, old_layer_count, format_, old_usage);
if (!allocate_status) {
ALOGE("DvrWriteBufferQueue::Dequeue: Failed to allocate buffer: %s",
allocate_status.GetErrorMessage().c_str());
}
void AllocateBuffers(size_t buffer_count) {
- size_t out_slot;
- for (size_t i = 0; i < buffer_count; i++) {
- auto status = write_queue_->producer_queue()->AllocateBuffer(
- kBufferWidth, kBufferHeight, kLayerCount, kBufferFormat, kBufferUsage,
- &out_slot);
- ASSERT_TRUE(status.ok());
- }
+ auto status = write_queue_->producer_queue()->AllocateBuffers(
+ kBufferWidth, kBufferHeight, kLayerCount, kBufferFormat, kBufferUsage,
+ buffer_count);
+ ASSERT_TRUE(status.ok());
}
void HandleBufferAvailable() {