diff options
Diffstat (limited to 'libs/gui')
48 files changed, 3365 insertions, 1583 deletions
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 02d29a3e69..b29c1d5157 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -19,7 +19,7 @@ cc_library_headers { cc_library_shared { name: "libgui", - vendor_available: true, + vendor_available: false, vndk: { enabled: true, }, @@ -63,6 +63,12 @@ cc_library_shared { // Allow documentation warnings "-Wno-documentation", + // Allow implicit instantiation for templated class function + "-Wno-undefined-func-template", + + // Allow explicitly marking struct as packed even when unnecessary + "-Wno-packed", + "-DDEBUG_ONLY_CODE=0", ], @@ -77,6 +83,8 @@ cc_library_shared { srcs: [ "BitTube.cpp", + "BufferHubConsumer.cpp", + "BufferHubProducer.cpp", "BufferItem.cpp", "BufferItemConsumer.cpp", "BufferQueue.cpp", @@ -90,6 +98,7 @@ cc_library_shared { "FrameTimestamps.cpp", "GLConsumer.cpp", "GuiConfig.cpp", + "HdrMetadata.cpp", "IDisplayEventConnection.cpp", "IConsumerListener.cpp", "IGraphicBufferConsumer.cpp", @@ -111,8 +120,11 @@ cc_library_shared { ], shared_libs: [ + "android.hardware.graphics.common@1.1", "libsync", "libbinder", + "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui. + "libpdx_default_transport", "libcutils", "libEGL", "libGLESv2", @@ -128,9 +140,26 @@ cc_library_shared { "android.hardware.configstore-utils", ], + // bufferhub is not used when building libgui for vendors + target: { + vendor: { + cflags: ["-DNO_BUFFERHUB"], + exclude_srcs: [ + "BufferHubConsumer.cpp", + "BufferHubProducer.cpp", + ], + exclude_shared_libs: [ + "libbufferhubqueue", + "libpdx_default_transport", + ], + }, + }, + header_libs: [ + "libdvr_headers", "libnativebase_headers", "libgui_headers", + "libpdx_headers", ], export_shared_lib_headers: [ @@ -140,6 +169,7 @@ cc_library_shared { "libui", "android.hidl.token@1.0-utils", "android.hardware.graphics.bufferqueue@1.0", + "android.hardware.graphics.common@1.1", ], export_header_lib_headers: [ diff --git a/libs/gui/BufferHubConsumer.cpp b/libs/gui/BufferHubConsumer.cpp new file mode 100644 index 0000000000..b5cdeb280a --- /dev/null +++ b/libs/gui/BufferHubConsumer.cpp @@ -0,0 +1,161 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gui/BufferHubConsumer.h> + +namespace android { + +using namespace dvr; + +/* static */ +sp<BufferHubConsumer> BufferHubConsumer::Create(const std::shared_ptr<ConsumerQueue>& queue) { + sp<BufferHubConsumer> consumer = new BufferHubConsumer; + consumer->mQueue = queue; + return consumer; +} + +/* static */ sp<BufferHubConsumer> BufferHubConsumer::Create(ConsumerQueueParcelable parcelable) { + if (!parcelable.IsValid()) { + ALOGE("BufferHubConsumer::Create: Invalid consumer parcelable."); + return nullptr; + } + + sp<BufferHubConsumer> consumer = new BufferHubConsumer; + consumer->mQueue = ConsumerQueue::Import(parcelable.TakeChannelHandle()); + return consumer; +} + +status_t BufferHubConsumer::acquireBuffer(BufferItem* /*buffer*/, nsecs_t /*presentWhen*/, + uint64_t /*maxFrameNumber*/) { + ALOGE("BufferHubConsumer::acquireBuffer: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::detachBuffer(int /*slot*/) { + ALOGE("BufferHubConsumer::detachBuffer: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::attachBuffer(int* /*outSlot*/, const sp<GraphicBuffer>& /*buffer*/) { + ALOGE("BufferHubConsumer::attachBuffer: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::releaseBuffer(int /*buf*/, uint64_t /*frameNumber*/, + EGLDisplay /*display*/, EGLSyncKHR /*fence*/, + const sp<Fence>& /*releaseFence*/) { + ALOGE("BufferHubConsumer::releaseBuffer: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::consumerConnect(const sp<IConsumerListener>& /*consumer*/, + bool /*controlledByApp*/) { + ALOGE("BufferHubConsumer::consumerConnect: not implemented."); + + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to + // make IGraphicBufferConsumer_test happy. + return NO_ERROR; +} + +status_t BufferHubConsumer::consumerDisconnect() { + ALOGE("BufferHubConsumer::consumerDisconnect: not implemented."); + + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to + // make IGraphicBufferConsumer_test happy. + return NO_ERROR; +} + +status_t BufferHubConsumer::getReleasedBuffers(uint64_t* /*slotMask*/) { + ALOGE("BufferHubConsumer::getReleasedBuffers: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) { + ALOGE("BufferHubConsumer::setDefaultBufferSize: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setMaxBufferCount(int /*bufferCount*/) { + ALOGE("BufferHubConsumer::setMaxBufferCount: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setMaxAcquiredBufferCount(int /*maxAcquiredBuffers*/) { + ALOGE("BufferHubConsumer::setMaxAcquiredBufferCount: not implemented."); + + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. Returns NO_ERROR to + // make IGraphicBufferConsumer_test happy. + return NO_ERROR; +} + +status_t BufferHubConsumer::setConsumerName(const String8& /*name*/) { + ALOGE("BufferHubConsumer::setConsumerName: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setDefaultBufferFormat(PixelFormat /*defaultFormat*/) { + ALOGE("BufferHubConsumer::setDefaultBufferFormat: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setDefaultBufferDataSpace(android_dataspace /*defaultDataSpace*/) { + ALOGE("BufferHubConsumer::setDefaultBufferDataSpace: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setConsumerUsageBits(uint64_t /*usage*/) { + ALOGE("BufferHubConsumer::setConsumerUsageBits: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setConsumerIsProtected(bool /*isProtected*/) { + ALOGE("BufferHubConsumer::setConsumerIsProtected: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::setTransformHint(uint32_t /*hint*/) { + ALOGE("BufferHubConsumer::setTransformHint: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::getSidebandStream(sp<NativeHandle>* /*outStream*/) const { + ALOGE("BufferHubConsumer::getSidebandStream: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::getOccupancyHistory( + bool /*forceFlush*/, std::vector<OccupancyTracker::Segment>* /*outHistory*/) { + ALOGE("BufferHubConsumer::getOccupancyHistory: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::discardFreeBuffers() { + ALOGE("BufferHubConsumer::discardFreeBuffers: not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubConsumer::dumpState(const String8& /*prefix*/, String8* /*outResult*/) const { + ALOGE("BufferHubConsumer::dumpState: not implemented."); + return INVALID_OPERATION; +} + +IBinder* BufferHubConsumer::onAsBinder() { + ALOGE("BufferHubConsumer::onAsBinder: BufferHubConsumer should never be used as an Binder " + "object."); + return nullptr; +} + +} // namespace android diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp new file mode 100644 index 0000000000..ae5cca2d20 --- /dev/null +++ b/libs/gui/BufferHubProducer.cpp @@ -0,0 +1,717 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <dvr/dvr_api.h> +#include <gui/BufferHubProducer.h> +#include <inttypes.h> +#include <log/log.h> +#include <system/window.h> + +namespace android { + +using namespace dvr; + +/* static */ +sp<BufferHubProducer> BufferHubProducer::Create(const std::shared_ptr<ProducerQueue>& queue) { + sp<BufferHubProducer> producer = new BufferHubProducer; + producer->queue_ = queue; + return producer; +} + +/* static */ +sp<BufferHubProducer> BufferHubProducer::Create(ProducerQueueParcelable parcelable) { + if (!parcelable.IsValid()) { + ALOGE("BufferHubProducer::Create: Invalid producer parcelable."); + return nullptr; + } + + sp<BufferHubProducer> producer = new BufferHubProducer; + producer->queue_ = ProducerQueue::Import(parcelable.TakeChannelHandle()); + return producer; +} + +status_t BufferHubProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { + ALOGV("requestBuffer: slot=%d", slot); + + std::unique_lock<std::mutex> lock(mutex_); + + if (connected_api_ == kNoConnectedApi) { + ALOGE("requestBuffer: BufferHubProducer 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, max_buffer_count_); + return BAD_VALUE; + } else if (!buffers_[slot].mBufferState.isDequeued()) { + ALOGE("requestBuffer: slot %d is not owned by the producer (state = %s)", slot, + buffers_[slot].mBufferState.string()); + return BAD_VALUE; + } else if (buffers_[slot].mGraphicBuffer != nullptr) { + ALOGE("requestBuffer: slot %d is not empty.", slot); + return BAD_VALUE; + } else if (buffers_[slot].mBufferProducer == nullptr) { + ALOGE("requestBuffer: slot %d is not dequeued.", slot); + return BAD_VALUE; + } + + const auto& buffer_producer = buffers_[slot].mBufferProducer; + sp<GraphicBuffer> graphic_buffer = buffer_producer->buffer()->buffer(); + + buffers_[slot].mGraphicBuffer = graphic_buffer; + buffers_[slot].mRequestBufferCalled = true; + + *buf = graphic_buffer; + return NO_ERROR; +} + +status_t BufferHubProducer::setMaxDequeuedBufferCount(int max_dequeued_buffers) { + ALOGV("setMaxDequeuedBufferCount: max_dequeued_buffers=%d", max_dequeued_buffers); + + std::unique_lock<std::mutex> lock(mutex_); + + if (max_dequeued_buffers <= 0 || + max_dequeued_buffers > + int(BufferHubQueue::kMaxQueueCapacity - kDefaultUndequeuedBuffers)) { + ALOGE("setMaxDequeuedBufferCount: %d out of range (0, %zu]", max_dequeued_buffers, + BufferHubQueue::kMaxQueueCapacity); + return BAD_VALUE; + } + + // The new dequeued_buffers count should not be violated by the number + // of currently dequeued buffers. + int dequeued_count = 0; + for (const auto& buf : 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 BufferHubProducer::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("BufferHubProducer::setAsyncMode: BufferHubQueue should always be " + "asynchronous. This call makes no effact."); + return NO_ERROR; + } + return NO_ERROR; +} + +status_t BufferHubProducer::dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width, + uint32_t height, PixelFormat format, uint64_t usage, + uint64_t* /*outBufferAge*/, + FrameEventHistoryDelta* /* out_timestamps */) { + ALOGV("dequeueBuffer: w=%u, h=%u, format=%d, usage=%" PRIu64, width, height, format, usage); + + status_t ret; + std::unique_lock<std::mutex> lock(mutex_); + + if (connected_api_ == kNoConnectedApi) { + ALOGE("dequeueBuffer: BufferQueue has no connected producer"); + return NO_INIT; + } + + const uint32_t kLayerCount = 1; + if (int32_t(queue_->capacity()) < max_dequeued_buffer_count_ + kDefaultUndequeuedBuffers) { + // Lazy allocation. When the capacity of |queue_| has not reached + // |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 = AllocateBuffer(width, height, kLayerCount, format, usage); + if (ret < 0) return ret; + } + + size_t slot = 0; + std::shared_ptr<BufferProducer> buffer_producer; + + for (size_t retry = 0; retry < BufferHubQueue::kMaxQueueCapacity; retry++) { + LocalHandle fence; + auto buffer_status = queue_->Dequeue(dequeue_timeout_ms_, &slot, &fence); + if (!buffer_status) return NO_MEMORY; + + buffer_producer = buffer_status.take(); + if (!buffer_producer) return NO_MEMORY; + + if (width == buffer_producer->width() && height == buffer_producer->height() && + uint32_t(format) == buffer_producer->format()) { + // The producer queue returns a buffer producer matches the request. + break; + } + + // Needs reallocation. + // TODO(jwcai) Consider use VLOG instead if we find this log is not useful. + ALOGI("dequeueBuffer: requested buffer (w=%u, h=%u, format=%u) is different " + "from the buffer returned at slot: %zu (w=%u, h=%u, format=%u). Need " + "re-allocattion.", + width, height, format, slot, buffer_producer->width(), buffer_producer->height(), + buffer_producer->format()); + // Mark the slot as reallocating, so that later we can set + // BUFFER_NEEDS_REALLOCATION when the buffer actually get dequeued. + buffers_[slot].mIsReallocating = true; + + // Remove the old buffer once the allocation before allocating its + // replacement. + RemoveBuffer(slot); + + // Allocate a new producer buffer with new buffer configs. Note that if + // there are already multiple buffers in the queue, the next one returned + // from |queue_->Dequeue| may not be the new buffer we just reallocated. + // Retry up to BufferHubQueue::kMaxQueueCapacity times. + ret = AllocateBuffer(width, height, kLayerCount, format, usage); + if (ret < 0) return ret; + } + + // With the BufferHub backed solution. Buffer slot returned from + // |queue_->Dequeue| is guaranteed to avaiable for producer's use. + // It's either in free state (if the buffer has never been used before) or + // in queued state (if the buffer has been dequeued and queued back to + // BufferHubQueue). + LOG_ALWAYS_FATAL_IF((!buffers_[slot].mBufferState.isFree() && + !buffers_[slot].mBufferState.isQueued()), + "dequeueBuffer: slot %zu is not free or queued, actual state: %s.", slot, + buffers_[slot].mBufferState.string()); + + buffers_[slot].mBufferState.freeQueued(); + buffers_[slot].mBufferState.dequeue(); + ALOGV("dequeueBuffer: slot=%zu", slot); + + // TODO(jwcai) Handle fence properly. |BufferHub| has full fence support, we + // just need to exopose that through |BufferHubQueue| once we need fence. + *out_fence = Fence::NO_FENCE; + *out_slot = int(slot); + ret = NO_ERROR; + + if (buffers_[slot].mIsReallocating) { + ret |= BUFFER_NEEDS_REALLOCATION; + buffers_[slot].mIsReallocating = false; + } + + return ret; +} + +status_t BufferHubProducer::detachBuffer(int /* slot */) { + ALOGE("BufferHubProducer::detachBuffer not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* /* out_buffer */, + sp<Fence>* /* out_fence */) { + ALOGE("BufferHubProducer::detachNextBuffer not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubProducer::attachBuffer(int* /* out_slot */, + const sp<GraphicBuffer>& /* buffer */) { + // With this BufferHub backed implementation, we assume (for now) all buffers + // are allocated and owned by the BufferHub. Thus the attempt of transfering + // ownership of a buffer to the buffer queue is intentionally unsupported. + LOG_ALWAYS_FATAL("BufferHubProducer::attachBuffer not supported."); + return INVALID_OPERATION; +} + +status_t BufferHubProducer::queueBuffer(int slot, const QueueBufferInput& input, + QueueBufferOutput* output) { + ALOGV("queueBuffer: slot %d", slot); + + if (output == nullptr) { + return BAD_VALUE; + } + + int64_t timestamp; + bool is_auto_timestamp; + android_dataspace dataspace; + Rect crop(Rect::EMPTY_RECT); + int scaling_mode; + uint32_t transform; + sp<Fence> fence; + + input.deflate(×tamp, &is_auto_timestamp, &dataspace, &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; + } + + std::unique_lock<std::mutex> lock(mutex_); + + if (connected_api_ == 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, max_buffer_count_); + return BAD_VALUE; + } else if (!buffers_[slot].mBufferState.isDequeued()) { + ALOGE("queueBuffer: slot %d is not owned by the producer (state = %s)", slot, + buffers_[slot].mBufferState.string()); + return BAD_VALUE; + } else if ((!buffers_[slot].mRequestBufferCalled || buffers_[slot].mGraphicBuffer == nullptr)) { + ALOGE("queueBuffer: slot %d is not requested (mRequestBufferCalled=%d, " + "mGraphicBuffer=%p)", + slot, buffers_[slot].mRequestBufferCalled, buffers_[slot].mGraphicBuffer.get()); + return BAD_VALUE; + } + + // Post the buffer producer with timestamp in the metadata. + const auto& buffer_producer = 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); + + DvrNativeBufferMetadata meta_data; + meta_data.timestamp = timestamp; + meta_data.is_auto_timestamp = int32_t(is_auto_timestamp); + meta_data.dataspace = 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 = int32_t(scaling_mode); + meta_data.transform = int32_t(transform); + + buffer_producer->PostAsync(&meta_data, fence_fd); + buffers_[slot].mBufferState.queue(); + + 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; +} + +status_t BufferHubProducer::cancelBuffer(int slot, const sp<Fence>& fence) { + ALOGV(__FUNCTION__); + + std::unique_lock<std::mutex> lock(mutex_); + + if (connected_api_ == 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, max_buffer_count_); + return BAD_VALUE; + } else if (!buffers_[slot].mBufferState.isDequeued()) { + ALOGE("cancelBuffer: slot %d is not owned by the producer (state = %s)", slot, + buffers_[slot].mBufferState.string()); + return BAD_VALUE; + } else if (fence == nullptr) { + ALOGE("cancelBuffer: fence is NULL"); + return BAD_VALUE; + } + + auto buffer_producer = buffers_[slot].mBufferProducer; + queue_->Enqueue(buffer_producer, size_t(slot), 0ULL); + buffers_[slot].mBufferState.cancel(); + buffers_[slot].mFence = fence; + ALOGV("cancelBuffer: slot %d", slot); + + return NO_ERROR; +} + +status_t BufferHubProducer::query(int what, int* out_value) { + ALOGV(__FUNCTION__); + + std::unique_lock<std::mutex> lock(mutex_); + + if (out_value == nullptr) { + ALOGE("query: out_value was NULL"); + return BAD_VALUE; + } + + int value = 0; + switch (what) { + case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: + // 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 = kDefaultUndequeuedBuffers; + break; + case NATIVE_WINDOW_BUFFER_AGE: + value = 0; + break; + case NATIVE_WINDOW_WIDTH: + value = int32_t(queue_->default_width()); + break; + case NATIVE_WINDOW_HEIGHT: + value = int32_t(queue_->default_height()); + break; + case NATIVE_WINDOW_FORMAT: + value = int32_t(queue_->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; + 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; + case NATIVE_WINDOW_CONSUMER_IS_PROTECTED: + // In Daydream's implementation, the consumer end (i.e. VR Compostior) + // knows how to handle protected buffers. + value = 1; + break; + default: + return BAD_VALUE; + } + + ALOGV("query: key=%d, v=%d", what, value); + *out_value = value; + return NO_ERROR; +} + +status_t BufferHubProducer::connect(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. We only need to perform basic input + // parameter checks here. + ALOGV(__FUNCTION__); + + if (output == nullptr) { + return BAD_VALUE; + } + + std::unique_lock<std::mutex> lock(mutex_); + + if (connected_api_ != kNoConnectedApi) { + return BAD_VALUE; + } + + if (!queue_->is_connected()) { + ALOGE("BufferHubProducer::connect: This BufferHubProducer is not " + "connected to bufferhud. Has it been taken out as a parcelable?"); + 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: + connected_api_ = api; + + output->width = queue_->default_width(); + output->height = queue_->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("BufferHubProducer::connect: unknow API %d", api); + return BAD_VALUE; + } + + return NO_ERROR; +} + +status_t BufferHubProducer::disconnect(int api, DisconnectMode /*mode*/) { + // Consumer interaction are actually handled by buffer hub, and we need + // to maintain consumer operations here. We only need to perform basic input + // parameter checks here. + ALOGV(__FUNCTION__); + + std::unique_lock<std::mutex> lock(mutex_); + + if (kNoConnectedApi == connected_api_) { + return NO_INIT; + } else if (api != connected_api_) { + return BAD_VALUE; + } + + FreeAllBuffers(); + connected_api_ = kNoConnectedApi; + return NO_ERROR; +} + +status_t BufferHubProducer::setSidebandStream(const sp<NativeHandle>& stream) { + if (stream != nullptr) { + // TODO(jwcai) Investigate how is is used, maybe use BufferHubBuffer's + // metadata. + ALOGE("SidebandStream is not currently supported."); + return INVALID_OPERATION; + } + return NO_ERROR; +} + +void BufferHubProducer::allocateBuffers(uint32_t /* width */, uint32_t /* height */, + PixelFormat /* format */, uint64_t /* usage */) { + // TODO(jwcai) |allocateBuffers| aims to preallocate up to the maximum number + // of buffers permitted by the current BufferQueue configuration (aka + // |max_buffer_count_|). + ALOGE("BufferHubProducer::allocateBuffers not implemented."); +} + +status_t BufferHubProducer::allowAllocation(bool /* allow */) { + ALOGE("BufferHubProducer::allowAllocation not implemented."); + return INVALID_OPERATION; +} + +status_t BufferHubProducer::setGenerationNumber(uint32_t generation_number) { + ALOGV(__FUNCTION__); + + std::unique_lock<std::mutex> lock(mutex_); + generation_number_ = generation_number; + return NO_ERROR; +} + +String8 BufferHubProducer::getConsumerName() const { + // BufferHub based implementation could have one to many producer/consumer + // relationship, thus |getConsumerName| from the producer side does not + // make any sense. + ALOGE("BufferHubProducer::getConsumerName not supported."); + return String8("BufferHubQueue::DummyConsumer"); +} + +status_t BufferHubProducer::setSharedBufferMode(bool shared_buffer_mode) { + if (shared_buffer_mode) { + ALOGE("BufferHubProducer::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 BufferHubProducer::setAutoRefresh(bool auto_refresh) { + if (auto_refresh) { + ALOGE("BufferHubProducer::setAutoRefresh(true) is not supported."); + return INVALID_OPERATION; + } + // Setting to default should just work as a no-op. + return NO_ERROR; +} + +status_t BufferHubProducer::setDequeueTimeout(nsecs_t timeout) { + ALOGV(__FUNCTION__); + + std::unique_lock<std::mutex> lock(mutex_); + dequeue_timeout_ms_ = static_cast<int>(timeout / (1000 * 1000)); + return NO_ERROR; +} + +status_t BufferHubProducer::getLastQueuedBuffer(sp<GraphicBuffer>* /* out_buffer */, + sp<Fence>* /* out_fence */, + float /*out_transform_matrix*/[16]) { + ALOGE("BufferHubProducer::getLastQueuedBuffer not implemented."); + return INVALID_OPERATION; +} + +void BufferHubProducer::getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) { + ALOGE("BufferHubProducer::getFrameTimestamps not implemented."); +} + +status_t BufferHubProducer::getUniqueId(uint64_t* out_id) const { + ALOGV(__FUNCTION__); + + *out_id = unique_id_; + return NO_ERROR; +} + +status_t BufferHubProducer::getConsumerUsage(uint64_t* out_usage) const { + ALOGV(__FUNCTION__); + + // same value as returned by querying NATIVE_WINDOW_CONSUMER_USAGE_BITS + *out_usage = 0; + return NO_ERROR; +} + +status_t BufferHubProducer::TakeAsParcelable(ProducerQueueParcelable* out_parcelable) { + if (!out_parcelable || out_parcelable->IsValid()) return BAD_VALUE; + + if (connected_api_ != kNoConnectedApi) { + ALOGE("BufferHubProducer::TakeAsParcelable: BufferHubProducer has " + "connected client. Must disconnect first."); + return BAD_VALUE; + } + + if (!queue_->is_connected()) { + ALOGE("BufferHubProducer::TakeAsParcelable: This BufferHubProducer " + "is not connected to bufferhud. Has it been taken out as a " + "parcelable?"); + return BAD_VALUE; + } + + auto status = queue_->TakeAsParcelable(); + if (!status) { + ALOGE("BufferHubProducer::TakeAsParcelable: Failed to take out " + "ProducuerQueueParcelable from the producer queue, error: %s.", + status.GetErrorMessage().c_str()); + return BAD_VALUE; + } + + *out_parcelable = status.take(); + return NO_ERROR; +} + +status_t BufferHubProducer::AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count, + PixelFormat format, uint64_t usage) { + auto status = queue_->AllocateBuffer(width, height, layer_count, uint32_t(format), usage); + if (!status) { + ALOGE("BufferHubProducer::AllocateBuffer: Failed to allocate buffer: %s", + status.GetErrorMessage().c_str()); + return NO_MEMORY; + } + + size_t slot = status.get(); + auto buffer_producer = queue_->GetBuffer(slot); + + LOG_ALWAYS_FATAL_IF(buffer_producer == nullptr, "Failed to get buffer producer at slot: %zu", + slot); + + buffers_[slot].mBufferProducer = buffer_producer; + + return NO_ERROR; +} + +status_t BufferHubProducer::RemoveBuffer(size_t slot) { + auto status = queue_->RemoveBuffer(slot); + if (!status) { + ALOGE("BufferHubProducer::RemoveBuffer: Failed to remove buffer: %s", + status.GetErrorMessage().c_str()); + return INVALID_OPERATION; + } + + // Reset in memory objects related the the buffer. + buffers_[slot].mBufferProducer = nullptr; + buffers_[slot].mGraphicBuffer = nullptr; + buffers_[slot].mBufferState.detachProducer(); + return NO_ERROR; +} + +status_t BufferHubProducer::FreeAllBuffers() { + for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) { + // Reset in memory objects related the the buffer. + buffers_[slot].mGraphicBuffer = nullptr; + buffers_[slot].mBufferState.reset(); + buffers_[slot].mRequestBufferCalled = false; + buffers_[slot].mBufferProducer = nullptr; + buffers_[slot].mFence = Fence::NO_FENCE; + } + + auto status = queue_->FreeAllBuffers(); + if (!status) { + ALOGE("BufferHubProducer::FreeAllBuffers: Failed to free all buffers on " + "the queue: %s", + status.GetErrorMessage().c_str()); + } + + if (queue_->capacity() != 0 || queue_->count() != 0) { + LOG_ALWAYS_FATAL("BufferHubProducer::FreeAllBuffers: Not all buffers are freed."); + } + + return NO_ERROR; +} + +status_t BufferHubProducer::exportToParcel(Parcel* parcel) { + status_t res = TakeAsParcelable(&pending_producer_parcelable_); + if (res != NO_ERROR) return res; + + if (!pending_producer_parcelable_.IsValid()) { + ALOGE("BufferHubProducer::exportToParcel: Invalid parcelable object."); + return BAD_VALUE; + } + + res = parcel->writeUint32(USE_BUFFER_HUB); + if (res != NO_ERROR) { + ALOGE("BufferHubProducer::exportToParcel: Cannot write magic, res=%d.", res); + return res; + } + + return pending_producer_parcelable_.writeToParcel(parcel); +} + +IBinder* BufferHubProducer::onAsBinder() { + ALOGE("BufferHubProducer::onAsBinder: BufferHubProducer should never be used as an Binder " + "object."); + return nullptr; +} + +} // namespace android diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp index 9da4ea80e0..f50379b3ed 100644 --- a/libs/gui/BufferItem.cpp +++ b/libs/gui/BufferItem.cpp @@ -39,8 +39,8 @@ static inline constexpr T to64(const uint32_t lo, const uint32_t hi) { } BufferItem::BufferItem() : - mGraphicBuffer(nullptr), - mFence(nullptr), + mGraphicBuffer(NULL), + mFence(NULL), mCrop(Rect::INVALID_RECT), mTransform(0), mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), @@ -55,7 +55,8 @@ BufferItem::BufferItem() : mSurfaceDamage(), mAutoRefresh(false), mQueuedBuffer(true), - mIsStale(false) { + mIsStale(false), + mApi(0) { } BufferItem::~BufferItem() {} @@ -84,30 +85,32 @@ size_t BufferItem::getPodSize() const { addAligned(size, mAutoRefresh); addAligned(size, mQueuedBuffer); addAligned(size, mIsStale); + addAligned(size, mApi); return size; } size_t BufferItem::getFlattenedSize() const { size_t size = sizeof(uint32_t); // Flags - if (mGraphicBuffer != nullptr) { + if (mGraphicBuffer != 0) { size += mGraphicBuffer->getFlattenedSize(); size = FlattenableUtils::align<4>(size); } - if (mFence != nullptr) { + if (mFence != 0) { size += mFence->getFlattenedSize(); size = FlattenableUtils::align<4>(size); } size += mSurfaceDamage.getFlattenedSize(); + size += mHdrMetadata.getFlattenedSize(); size = FlattenableUtils::align<8>(size); return size + getPodSize(); } size_t BufferItem::getFdCount() const { size_t count = 0; - if (mGraphicBuffer != nullptr) { + if (mGraphicBuffer != 0) { count += mGraphicBuffer->getFdCount(); } - if (mFence != nullptr) { + if (mFence != 0) { count += mFence->getFdCount(); } return count; @@ -134,13 +137,13 @@ status_t BufferItem::flatten( FlattenableUtils::advance(buffer, size, sizeof(uint32_t)); flags = 0; - if (mGraphicBuffer != nullptr) { + if (mGraphicBuffer != 0) { status_t err = mGraphicBuffer->flatten(buffer, size, fds, count); if (err) return err; size -= FlattenableUtils::align<4>(buffer); flags |= 1; } - if (mFence != nullptr) { + if (mFence != 0) { status_t err = mFence->flatten(buffer, size, fds, count); if (err) return err; size -= FlattenableUtils::align<4>(buffer); @@ -151,6 +154,10 @@ status_t BufferItem::flatten( if (err) return err; FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize()); + err = mHdrMetadata.flatten(buffer, size); + if (err) return err; + FlattenableUtils::advance(buffer, size, mHdrMetadata.getFlattenedSize()); + // Check we still have enough space if (size < getPodSize()) { return NO_MEMORY; @@ -172,6 +179,7 @@ status_t BufferItem::flatten( writeAligned(buffer, size, mAutoRefresh); writeAligned(buffer, size, mQueuedBuffer); writeAligned(buffer, size, mIsStale); + writeAligned(buffer, size, mApi); return NO_ERROR; } @@ -212,6 +220,10 @@ status_t BufferItem::unflatten( if (err) return err; FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize()); + err = mHdrMetadata.unflatten(buffer, size); + if (err) return err; + FlattenableUtils::advance(buffer, size, mHdrMetadata.getFlattenedSize()); + // Check we still have enough space if (size < getPodSize()) { return NO_MEMORY; @@ -238,6 +250,7 @@ status_t BufferItem::unflatten( readAligned(buffer, size, mAutoRefresh); readAligned(buffer, size, mQueuedBuffer); readAligned(buffer, size, mIsStale); + readAligned(buffer, size, mApi); return NO_ERROR; } diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index 3aa4e449cc..89bc0c4c2d 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -49,16 +49,6 @@ BufferItemConsumer::BufferItemConsumer( BufferItemConsumer::~BufferItemConsumer() {} -void BufferItemConsumer::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - if (mAbandoned) { - BI_LOGE("setName: BufferItemConsumer is abandoned!"); - return; - } - mName = name; - mConsumer->setConsumerName(name); -} - void BufferItemConsumer::setBufferFreedListener( const wp<BufferFreedListener>& listener) { Mutex::Autolock _l(mMutex); @@ -102,10 +92,13 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, Mutex::Autolock _l(mMutex); err = addReleaseFenceLocked(item.mSlot, item.mGraphicBuffer, releaseFence); + if (err != OK) { + BI_LOGE("Failed to addReleaseFenceLocked"); + } err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); - if (err != OK) { + if (err != OK && err != IGraphicBufferConsumer::STALE_BUFFER_SLOT) { BI_LOGE("Failed to release buffer: %s (%d)", strerror(-err), err); } @@ -114,7 +107,7 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, void BufferItemConsumer::freeBufferLocked(int slotIndex) { sp<BufferFreedListener> listener = mBufferFreedListener.promote(); - if (listener != nullptr && mSlots[slotIndex].mGraphicBuffer != nullptr) { + if (listener != NULL && mSlots[slotIndex].mGraphicBuffer != NULL) { // Fire callback if we have a listener registered and the buffer being freed is valid. BI_LOGV("actually calling onBufferFreed"); listener->onBufferFreed(mSlots[slotIndex].mGraphicBuffer); diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 7da4db4d3f..a8da1347cb 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -18,6 +18,11 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 +#ifndef NO_BUFFERHUB +#include <gui/BufferHubConsumer.h> +#include <gui/BufferHubProducer.h> +#endif + #include <gui/BufferQueue.h> #include <gui/BufferQueueConsumer.h> #include <gui/BufferQueueCore.h> @@ -33,7 +38,7 @@ BufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} void BufferQueue::ProxyConsumerListener::onDisconnect() { sp<ConsumerListener> listener(mConsumerListener.promote()); - if (listener != nullptr) { + if (listener != NULL) { listener->onDisconnect(); } } @@ -41,7 +46,7 @@ void BufferQueue::ProxyConsumerListener::onDisconnect() { void BufferQueue::ProxyConsumerListener::onFrameAvailable( const BufferItem& item) { sp<ConsumerListener> listener(mConsumerListener.promote()); - if (listener != nullptr) { + if (listener != NULL) { listener->onFrameAvailable(item); } } @@ -49,21 +54,21 @@ void BufferQueue::ProxyConsumerListener::onFrameAvailable( void BufferQueue::ProxyConsumerListener::onFrameReplaced( const BufferItem& item) { sp<ConsumerListener> listener(mConsumerListener.promote()); - if (listener != nullptr) { + if (listener != NULL) { listener->onFrameReplaced(item); } } void BufferQueue::ProxyConsumerListener::onBuffersReleased() { sp<ConsumerListener> listener(mConsumerListener.promote()); - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } } void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() { sp<ConsumerListener> listener(mConsumerListener.promote()); - if (listener != nullptr) { + if (listener != NULL) { listener->onSidebandStreamChanged(); } } @@ -80,25 +85,53 @@ void BufferQueue::ProxyConsumerListener::addAndGetFrameTimestamps( void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer, bool consumerIsSurfaceFlinger) { - LOG_ALWAYS_FATAL_IF(outProducer == nullptr, + LOG_ALWAYS_FATAL_IF(outProducer == NULL, "BufferQueue: outProducer must not be NULL"); - LOG_ALWAYS_FATAL_IF(outConsumer == nullptr, + LOG_ALWAYS_FATAL_IF(outConsumer == NULL, "BufferQueue: outConsumer must not be NULL"); sp<BufferQueueCore> core(new BufferQueueCore()); - LOG_ALWAYS_FATAL_IF(core == nullptr, + LOG_ALWAYS_FATAL_IF(core == NULL, "BufferQueue: failed to create BufferQueueCore"); sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger)); - LOG_ALWAYS_FATAL_IF(producer == nullptr, + LOG_ALWAYS_FATAL_IF(producer == NULL, "BufferQueue: failed to create BufferQueueProducer"); sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core)); - LOG_ALWAYS_FATAL_IF(consumer == nullptr, + LOG_ALWAYS_FATAL_IF(consumer == NULL, "BufferQueue: failed to create BufferQueueConsumer"); *outProducer = producer; *outConsumer = consumer; } +#ifndef NO_BUFFERHUB +void BufferQueue::createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer, + sp<IGraphicBufferConsumer>* outConsumer) { + LOG_ALWAYS_FATAL_IF(outProducer == NULL, "BufferQueue: outProducer must not be NULL"); + LOG_ALWAYS_FATAL_IF(outConsumer == NULL, "BufferQueue: outConsumer must not be NULL"); + + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + + dvr::ProducerQueueConfigBuilder configBuilder; + std::shared_ptr<dvr::ProducerQueue> producerQueue = + dvr::ProducerQueue::Create(configBuilder.Build(), dvr::UsagePolicy{}); + LOG_ALWAYS_FATAL_IF(producerQueue == NULL, "BufferQueue: failed to create ProducerQueue."); + + std::shared_ptr<dvr::ConsumerQueue> consumerQueue = producerQueue->CreateConsumerQueue(); + LOG_ALWAYS_FATAL_IF(consumerQueue == NULL, "BufferQueue: failed to create ConsumerQueue."); + + producer = BufferHubProducer::Create(producerQueue); + consumer = BufferHubConsumer::Create(consumerQueue); + + LOG_ALWAYS_FATAL_IF(producer == NULL, "BufferQueue: failed to create BufferQueueProducer"); + LOG_ALWAYS_FATAL_IF(consumer == NULL, "BufferQueue: failed to create BufferQueueConsumer"); + + *outProducer = producer; + *outConsumer = consumer; +} +#endif + }; // namespace android diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 31eb29b8f6..d70e1422b0 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -35,7 +35,9 @@ #include <gui/IProducerListener.h> #include <binder/IPCThreadState.h> +#ifndef __ANDROID_VNDK__ #include <binder/PermissionCache.h> +#endif #include <system/window.h> @@ -253,7 +255,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer // on the consumer side if (outBuffer->mAcquireCalled) { - outBuffer->mGraphicBuffer = nullptr; + outBuffer->mGraphicBuffer = NULL; } mCore->mQueue.erase(front); @@ -270,7 +272,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, VALIDATE_CONSISTENCY(); } - if (listener != nullptr) { + if (listener != NULL) { for (int i = 0; i < numDroppedBuffers; ++i) { listener->onBufferReleased(); } @@ -319,10 +321,10 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot, const sp<android::GraphicBuffer>& buffer) { ATRACE_CALL(); - if (outSlot == nullptr) { + if (outSlot == NULL) { BQ_LOGE("attachBuffer: outSlot must not be NULL"); return BAD_VALUE; - } else if (buffer == nullptr) { + } else if (buffer == NULL) { BQ_LOGE("attachBuffer: cannot attach NULL buffer"); return BAD_VALUE; } @@ -411,7 +413,7 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, ATRACE_BUFFER_INDEX(slot); if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS || - releaseFence == nullptr) { + releaseFence == NULL) { BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot, releaseFence.get()); return BAD_VALUE; @@ -463,7 +465,7 @@ status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, } // Autolock scope // Call back without lock held - if (listener != nullptr) { + if (listener != NULL) { listener->onBufferReleased(); } @@ -474,7 +476,7 @@ status_t BufferQueueConsumer::connect( const sp<IConsumerListener>& consumerListener, bool controlledByApp) { ATRACE_CALL(); - if (consumerListener == nullptr) { + if (consumerListener == NULL) { BQ_LOGE("connect: consumerListener may not be NULL"); return BAD_VALUE; } @@ -502,13 +504,13 @@ status_t BufferQueueConsumer::disconnect() { Mutex::Autolock lock(mCore->mMutex); - if (mCore->mConsumerListener == nullptr) { + if (mCore->mConsumerListener == NULL) { BQ_LOGE("disconnect: no consumer is connected"); return BAD_VALUE; } mCore->mIsAbandoned = true; - mCore->mConsumerListener = nullptr; + mCore->mConsumerListener = NULL; mCore->mQueue.clear(); mCore->freeAllBuffersLocked(); mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT; @@ -519,7 +521,7 @@ status_t BufferQueueConsumer::disconnect() { status_t BufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) { ATRACE_CALL(); - if (outSlotMask == nullptr) { + if (outSlotMask == NULL) { BQ_LOGE("getReleasedBuffers: outSlotMask may not be NULL"); return BAD_VALUE; } @@ -671,7 +673,7 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount( } } // Call back without lock held - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } @@ -757,14 +759,20 @@ status_t BufferQueueConsumer::dumpState(const String8& prefix, String8* outResul } const IPCThreadState* ipc = IPCThreadState::self(); - const pid_t pid = ipc->getCallingPid(); const uid_t uid = ipc->getCallingUid(); +#ifndef __ANDROID_VNDK__ + // permission check can't be done for vendors as vendors have no access to + // the PermissionController + const pid_t pid = ipc->getCallingPid(); if ((uid != shellUid) && !PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) { outResult->appendFormat("Permission Denial: can't dump BufferQueueConsumer " "from pid=%d, uid=%d\n", pid, uid); +#else + if (uid != shellUid) { +#endif android_errorWriteWithInfoLog(0x534e4554, "27046057", - static_cast<int32_t>(uid), nullptr, 0); + static_cast<int32_t>(uid), NULL, 0); return PERMISSION_DENIED; } diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 0c7b7e20db..c8021e4d54 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -166,7 +166,7 @@ status_t BufferQueueProducer::setMaxDequeuedBufferCount( } // Autolock scope // Call back without lock held - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } @@ -221,7 +221,7 @@ status_t BufferQueueProducer::setAsyncMode(bool async) { } // Autolock scope // Call back without lock held - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } return NO_ERROR; @@ -450,11 +450,11 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* ou mSlots[found].mBufferState.dequeue(); - if ((buffer == nullptr) || + if ((buffer == NULL) || buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage)) { mSlots[found].mAcquireCalled = false; - mSlots[found].mGraphicBuffer = nullptr; + mSlots[found].mGraphicBuffer = NULL; mSlots[found].mRequestBufferCalled = false; mSlots[found].mEglDisplay = EGL_NO_DISPLAY; mSlots[found].mEglFence = EGL_NO_SYNC_KHR; @@ -472,7 +472,7 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* ou BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64, mCore->mBufferAge); - if (CC_UNLIKELY(mSlots[found].mFence == nullptr)) { + if (CC_UNLIKELY(mSlots[found].mFence == NULL)) { BQ_LOGE("dequeueBuffer: about to return a NULL fence - " "slot=%d w=%d h=%d format=%u", found, buffer->width, buffer->height, buffer->format); @@ -613,7 +613,7 @@ status_t BufferQueueProducer::detachBuffer(int slot) { listener = mCore->mConsumerListener; } - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } @@ -624,10 +624,10 @@ status_t BufferQueueProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) { ATRACE_CALL(); - if (outBuffer == nullptr) { + if (outBuffer == NULL) { BQ_LOGE("detachNextBuffer: outBuffer must not be NULL"); return BAD_VALUE; - } else if (outFence == nullptr) { + } else if (outFence == NULL) { BQ_LOGE("detachNextBuffer: outFence must not be NULL"); return BAD_VALUE; } @@ -671,7 +671,7 @@ status_t BufferQueueProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer, listener = mCore->mConsumerListener; } - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); } @@ -682,10 +682,10 @@ status_t BufferQueueProducer::attachBuffer(int* outSlot, const sp<android::GraphicBuffer>& buffer) { ATRACE_CALL(); - if (outSlot == nullptr) { + if (outSlot == NULL) { BQ_LOGE("attachBuffer: outSlot must not be NULL"); return BAD_VALUE; - } else if (buffer == nullptr) { + } else if (buffer == NULL) { BQ_LOGE("attachBuffer: cannot attach NULL buffer"); return BAD_VALUE; } @@ -765,8 +765,9 @@ status_t BufferQueueProducer::queueBuffer(int slot, &crop, &scalingMode, &transform, &acquireFence, &stickyTransform, &getFrameTimestamps); const Region& surfaceDamage = input.getSurfaceDamage(); + const HdrMetadata& hdrMetadata = input.getHdrMetadata(); - if (acquireFence == nullptr) { + if (acquireFence == NULL) { BQ_LOGE("queueBuffer: fence is NULL"); return BAD_VALUE; } @@ -825,9 +826,9 @@ status_t BufferQueueProducer::queueBuffer(int slot, } BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " dataSpace=%d" - " crop=[%d,%d,%d,%d] transform=%#x scale=%s", - slot, mCore->mFrameCounter + 1, requestedPresentTimestamp, - dataSpace, crop.left, crop.top, crop.right, crop.bottom, + " validHdrMetadataTypes=0x%x crop=[%d,%d,%d,%d] transform=%#x scale=%s", + slot, mCore->mFrameCounter + 1, requestedPresentTimestamp, dataSpace, + hdrMetadata.validTypes, crop.left, crop.top, crop.right, crop.bottom, transform, BufferItem::scalingModeName(static_cast<uint32_t>(scalingMode))); @@ -866,6 +867,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, item.mTimestamp = requestedPresentTimestamp; item.mIsAutoTimestamp = isAutoTimestamp; item.mDataSpace = dataSpace; + item.mHdrMetadata = hdrMetadata; item.mFrameNumber = currentFrameNumber; item.mSlot = slot; item.mFence = acquireFence; @@ -876,6 +878,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, item.mSurfaceDamage = surfaceDamage; item.mQueuedBuffer = true; item.mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh; + item.mApi = mCore->mConnectedApi; mStickyTransform = stickyTransform; @@ -970,9 +973,9 @@ status_t BufferQueueProducer::queueBuffer(int slot, mCallbackCondition.wait(mCallbackMutex); } - if (frameAvailableListener != nullptr) { + if (frameAvailableListener != NULL) { frameAvailableListener->onFrameAvailable(item); - } else if (frameReplacedListener != nullptr) { + } else if (frameReplacedListener != NULL) { frameReplacedListener->onFrameReplaced(item); } @@ -1037,7 +1040,7 @@ status_t BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) { BQ_LOGE("cancelBuffer: slot %d is not owned by the producer " "(state = %s)", slot, mSlots[slot].mBufferState.string()); return BAD_VALUE; - } else if (fence == nullptr) { + } else if (fence == NULL) { BQ_LOGE("cancelBuffer: fence is NULL"); return BAD_VALUE; } @@ -1067,7 +1070,7 @@ int BufferQueueProducer::query(int what, int *outValue) { ATRACE_CALL(); Mutex::Autolock lock(mCore->mMutex); - if (outValue == nullptr) { + if (outValue == NULL) { BQ_LOGE("query: outValue was NULL"); return BAD_VALUE; } @@ -1118,6 +1121,9 @@ int BufferQueueProducer::query(int what, int *outValue) { case NATIVE_WINDOW_CONSUMER_IS_PROTECTED: value = static_cast<int32_t>(mCore->mConsumerIsProtected); break; + case NATIVE_WINDOW_MAX_BUFFER_COUNT: + value = static_cast<int32_t>(mCore->mMaxBufferCount); + break; default: return BAD_VALUE; } @@ -1140,12 +1146,12 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, return NO_INIT; } - if (mCore->mConsumerListener == nullptr) { + if (mCore->mConsumerListener == NULL) { BQ_LOGE("connect: BufferQueue has no consumer"); return NO_INIT; } - if (output == nullptr) { + if (output == NULL) { BQ_LOGE("connect: output was NULL"); return BAD_VALUE; } @@ -1183,10 +1189,10 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, output->nextFrameNumber = mCore->mFrameCounter + 1; output->bufferReplaced = false; - if (listener != nullptr) { + if (listener != NULL) { // Set up a death notification so that we can disconnect // automatically if the remote producer dies - if (IInterface::asBinder(listener)->remoteBinder() != nullptr) { + if (IInterface::asBinder(listener)->remoteBinder() != NULL) { status = IInterface::asBinder(listener)->linkToDeath( static_cast<IBinder::DeathRecipient*>(this)); if (status != NO_ERROR) { @@ -1263,7 +1269,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { mCore->freeAllBuffersLocked(); // Remove our death notification callback if we have one - if (mCore->mLinkedToDeath != nullptr) { + if (mCore->mLinkedToDeath != NULL) { sp<IBinder> token = IInterface::asBinder(mCore->mLinkedToDeath); // This can fail if we're here because of the death @@ -1273,8 +1279,8 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { } mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT; - mCore->mLinkedToDeath = nullptr; - mCore->mConnectedProducerListener = nullptr; + mCore->mLinkedToDeath = NULL; + mCore->mConnectedProducerListener = NULL; mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API; mCore->mConnectedPid = -1; mCore->mSidebandStream.clear(); @@ -1297,7 +1303,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { } // Autolock scope // Call back without lock held - if (listener != nullptr) { + if (listener != NULL) { listener->onBuffersReleased(); listener->onDisconnect(); } @@ -1313,7 +1319,7 @@ status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) listener = mCore->mConsumerListener; } // Autolock scope - if (listener != nullptr) { + if (listener != NULL) { listener->onSidebandStreamChanged(); } return NO_ERROR; @@ -1328,6 +1334,7 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, uint32_t allocHeight = 0; PixelFormat allocFormat = PIXEL_FORMAT_UNKNOWN; uint64_t allocUsage = 0; + std::string allocName; { // Autolock scope Mutex::Autolock lock(mCore->mMutex); mCore->waitWhileAllocatingLocked(); @@ -1347,6 +1354,7 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, allocHeight = height > 0 ? height : mCore->mDefaultHeight; allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat; allocUsage = usage | mCore->mConsumerUsageBits; + allocName.assign(mCore->mConsumerName.string(), mCore->mConsumerName.size()); mCore->mIsAllocating = true; } // Autolock scope @@ -1355,7 +1363,7 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, for (size_t i = 0; i < newBufferCount; ++i) { sp<GraphicBuffer> graphicBuffer = new GraphicBuffer( allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT, - allocUsage, {mConsumerName.string(), mConsumerName.size()}); + allocUsage, allocName); status_t result = graphicBuffer->initCheck(); @@ -1527,7 +1535,7 @@ void BufferQueueProducer::addAndGetFrameTimestamps( Mutex::Autolock lock(mCore->mMutex); listener = mCore->mConsumerListener; } - if (listener != nullptr) { + if (listener != NULL) { listener->addAndGetFrameTimestamps(newTimestamps, outDelta); } } diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 2a9d742fc9..f9e292e199 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -96,7 +96,7 @@ void ConsumerBase::onLastStrongRef(const void* id __attribute__((unused))) { void ConsumerBase::freeBufferLocked(int slotIndex) { CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); - mSlots[slotIndex].mGraphicBuffer = nullptr; + mSlots[slotIndex].mGraphicBuffer = 0; mSlots[slotIndex].mFence = Fence::NO_FENCE; mSlots[slotIndex].mFrameNumber = 0; } @@ -110,7 +110,7 @@ void ConsumerBase::onFrameAvailable(const BufferItem& item) { listener = mFrameAvailableListener.promote(); } - if (listener != nullptr) { + if (listener != NULL) { CB_LOGV("actually calling onFrameAvailable"); listener->onFrameAvailable(item); } @@ -125,7 +125,7 @@ void ConsumerBase::onFrameReplaced(const BufferItem &item) { listener = mFrameAvailableListener.promote(); } - if (listener != nullptr) { + if (listener != NULL) { CB_LOGV("actually calling onFrameReplaced"); listener->onFrameReplaced(item); } @@ -182,6 +182,16 @@ bool ConsumerBase::isAbandoned() { return mAbandoned; } +void ConsumerBase::setName(const String8& name) { + Mutex::Autolock _l(mMutex); + if (mAbandoned) { + CB_LOGE("setName: ConsumerBase is abandoned!"); + return; + } + mName = name; + mConsumer->setConsumerName(name); +} + void ConsumerBase::setFrameAvailableListener( const wp<FrameAvailableListener>& listener) { CB_LOGV("setFrameAvailableListener"); @@ -237,6 +247,50 @@ status_t ConsumerBase::setDefaultBufferDataSpace( return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); } +status_t ConsumerBase::setConsumerUsageBits(uint64_t usage) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + CB_LOGE("setConsumerUsageBits: ConsumerBase is abandoned!"); + return NO_INIT; + } + return mConsumer->setConsumerUsageBits(usage); +} + +status_t ConsumerBase::setTransformHint(uint32_t hint) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + CB_LOGE("setTransformHint: ConsumerBase is abandoned!"); + return NO_INIT; + } + return mConsumer->setTransformHint(hint); +} + +status_t ConsumerBase::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + CB_LOGE("setMaxAcquiredBufferCount: ConsumerBase is abandoned!"); + return NO_INIT; + } + return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers); +} + +sp<NativeHandle> ConsumerBase::getSidebandStream() const { + Mutex::Autolock _l(mMutex); + if (mAbandoned) { + CB_LOGE("getSidebandStream: ConsumerBase is abandoned!"); + return nullptr; + } + + sp<NativeHandle> stream; + status_t err = mConsumer->getSidebandStream(&stream); + if (err != NO_ERROR) { + CB_LOGE("failed to get sideband stream: %d", err); + return nullptr; + } + + return stream; +} + status_t ConsumerBase::getOccupancyHistory(bool forceFlush, std::vector<OccupancyTracker::Segment>* outHistory) { Mutex::Autolock _l(mMutex); @@ -298,8 +352,8 @@ status_t ConsumerBase::acquireBufferLocked(BufferItem *item, return err; } - if (item->mGraphicBuffer != nullptr) { - if (mSlots[item->mSlot].mGraphicBuffer != nullptr) { + if (item->mGraphicBuffer != NULL) { + if (mSlots[item->mSlot].mGraphicBuffer != NULL) { freeBufferLocked(item->mSlot); } mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer; @@ -414,7 +468,7 @@ bool ConsumerBase::stillTracking(int slot, if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) { return false; } - return (mSlots[slot].mGraphicBuffer != nullptr && + return (mSlots[slot].mGraphicBuffer != NULL && mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle); } diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp index 9f09e0c0d4..8edf60400c 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -18,11 +18,11 @@ #define LOG_TAG "CpuConsumer" //#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include <cutils/compiler.h> -#include <utils/Log.h> -#include <gui/BufferItem.h> #include <gui/CpuConsumer.h> +#include <gui/BufferItem.h> +#include <utils/Log.h> + #define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) //#define CC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) //#define CC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) @@ -44,20 +44,19 @@ CpuConsumer::CpuConsumer(const sp<IGraphicBufferConsumer>& bq, mConsumer->setMaxAcquiredBufferCount(static_cast<int32_t>(maxLockedBuffers)); } -CpuConsumer::~CpuConsumer() { - // ConsumerBase destructor does all the work. +size_t CpuConsumer::findAcquiredBufferLocked(uintptr_t id) const { + for (size_t i = 0; i < mMaxLockedBuffers; i++) { + const auto& ab = mAcquiredBuffers[i]; + // note that this finds AcquiredBuffer::kUnusedId as well + if (ab.mLockedBufferId == id) { + return i; + } + } + return mMaxLockedBuffers; // an invalid index } - - -void CpuConsumer::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - if (mAbandoned) { - CC_LOGE("setName: CpuConsumer is abandoned!"); - return; - } - mName = name; - mConsumer->setConsumerName(name); +static uintptr_t getLockedBufferId(const CpuConsumer::LockedBuffer& buffer) { + return reinterpret_cast<uintptr_t>(buffer.data); } static bool isPossiblyYUV(PixelFormat format) { @@ -88,10 +87,74 @@ static bool isPossiblyYUV(PixelFormat format) { } } +status_t CpuConsumer::lockBufferItem(const BufferItem& item, LockedBuffer* outBuffer) const { + android_ycbcr ycbcr = android_ycbcr(); + + PixelFormat format = item.mGraphicBuffer->getPixelFormat(); + PixelFormat flexFormat = format; + if (isPossiblyYUV(format)) { + int fenceFd = item.mFence.get() ? item.mFence->dup() : -1; + status_t err = item.mGraphicBuffer->lockAsyncYCbCr(GraphicBuffer::USAGE_SW_READ_OFTEN, + item.mCrop, &ycbcr, fenceFd); + if (err == OK) { + flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888; + if (format != HAL_PIXEL_FORMAT_YCbCr_420_888) { + CC_LOGV("locking buffer of format %#x as flex YUV", format); + } + } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) { + CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)", strerror(-err), err); + return err; + } + } + + if (ycbcr.y != nullptr) { + outBuffer->data = reinterpret_cast<uint8_t*>(ycbcr.y); + outBuffer->stride = static_cast<uint32_t>(ycbcr.ystride); + outBuffer->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb); + outBuffer->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr); + outBuffer->chromaStride = static_cast<uint32_t>(ycbcr.cstride); + outBuffer->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step); + } else { + // not flexible YUV; try lockAsync + void* bufferPointer = nullptr; + int fenceFd = item.mFence.get() ? item.mFence->dup() : -1; + status_t err = item.mGraphicBuffer->lockAsync(GraphicBuffer::USAGE_SW_READ_OFTEN, + item.mCrop, &bufferPointer, fenceFd); + if (err != OK) { + CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err), err); + return err; + } + + outBuffer->data = reinterpret_cast<uint8_t*>(bufferPointer); + outBuffer->stride = item.mGraphicBuffer->getStride(); + outBuffer->dataCb = nullptr; + outBuffer->dataCr = nullptr; + outBuffer->chromaStride = 0; + outBuffer->chromaStep = 0; + } + + outBuffer->width = item.mGraphicBuffer->getWidth(); + outBuffer->height = item.mGraphicBuffer->getHeight(); + outBuffer->format = format; + outBuffer->flexFormat = flexFormat; + + outBuffer->crop = item.mCrop; + outBuffer->transform = item.mTransform; + outBuffer->scalingMode = item.mScalingMode; + outBuffer->timestamp = item.mTimestamp; + outBuffer->dataSpace = item.mDataSpace; + outBuffer->frameNumber = item.mFrameNumber; + + return OK; +} + status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { status_t err; if (!nativeBuffer) return BAD_VALUE; + + Mutex::Autolock _l(mMutex); + if (mCurrentLockedBuffers == mMaxLockedBuffers) { CC_LOGW("Max buffers have been locked (%zd), cannot lock anymore.", mMaxLockedBuffers); @@ -99,9 +162,6 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { } BufferItem b; - - Mutex::Autolock _l(mMutex); - err = acquireBufferLocked(&b, 0); if (err != OK) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { @@ -112,94 +172,23 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { } } - int slot = b.mSlot; - - void *bufferPointer = nullptr; - android_ycbcr ycbcr = android_ycbcr(); - - PixelFormat format = mSlots[slot].mGraphicBuffer->getPixelFormat(); - PixelFormat flexFormat = format; - if (isPossiblyYUV(format)) { - if (b.mFence.get()) { - err = mSlots[slot].mGraphicBuffer->lockAsyncYCbCr( - GraphicBuffer::USAGE_SW_READ_OFTEN, - b.mCrop, - &ycbcr, - b.mFence->dup()); - } else { - err = mSlots[slot].mGraphicBuffer->lockYCbCr( - GraphicBuffer::USAGE_SW_READ_OFTEN, - b.mCrop, - &ycbcr); - } - if (err == OK) { - bufferPointer = ycbcr.y; - flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888; - if (format != HAL_PIXEL_FORMAT_YCbCr_420_888) { - CC_LOGV("locking buffer of format %#x as flex YUV", format); - } - } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) { - CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)", - strerror(-err), err); - return err; - } + if (b.mGraphicBuffer == nullptr) { + b.mGraphicBuffer = mSlots[b.mSlot].mGraphicBuffer; } - if (bufferPointer == nullptr) { // not flexible YUV - if (b.mFence.get()) { - err = mSlots[slot].mGraphicBuffer->lockAsync( - GraphicBuffer::USAGE_SW_READ_OFTEN, - b.mCrop, - &bufferPointer, - b.mFence->dup()); - } else { - err = mSlots[slot].mGraphicBuffer->lock( - GraphicBuffer::USAGE_SW_READ_OFTEN, - b.mCrop, - &bufferPointer); - } - if (err != OK) { - CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", - strerror(-err), err); - return err; - } + err = lockBufferItem(b, nativeBuffer); + if (err != OK) { + return err; } - size_t lockedIdx = 0; - for (; lockedIdx < static_cast<size_t>(mMaxLockedBuffers); lockedIdx++) { - if (mAcquiredBuffers[lockedIdx].mSlot == - BufferQueue::INVALID_BUFFER_SLOT) { - break; - } - } - assert(lockedIdx < mMaxLockedBuffers); - - AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx); - ab.mSlot = slot; - ab.mBufferPointer = bufferPointer; - ab.mGraphicBuffer = mSlots[slot].mGraphicBuffer; - - nativeBuffer->data = - reinterpret_cast<uint8_t*>(bufferPointer); - nativeBuffer->width = mSlots[slot].mGraphicBuffer->getWidth(); - nativeBuffer->height = mSlots[slot].mGraphicBuffer->getHeight(); - nativeBuffer->format = format; - nativeBuffer->flexFormat = flexFormat; - nativeBuffer->stride = (ycbcr.y != nullptr) ? - static_cast<uint32_t>(ycbcr.ystride) : - mSlots[slot].mGraphicBuffer->getStride(); - - nativeBuffer->crop = b.mCrop; - nativeBuffer->transform = b.mTransform; - nativeBuffer->scalingMode = b.mScalingMode; - nativeBuffer->timestamp = b.mTimestamp; - nativeBuffer->dataSpace = b.mDataSpace; - nativeBuffer->frameNumber = b.mFrameNumber; - - nativeBuffer->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb); - nativeBuffer->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr); - nativeBuffer->chromaStride = static_cast<uint32_t>(ycbcr.cstride); - nativeBuffer->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step); + // find an unused AcquiredBuffer + size_t lockedIdx = findAcquiredBufferLocked(AcquiredBuffer::kUnusedId); + ALOG_ASSERT(lockedIdx < mMaxLockedBuffers); + AcquiredBuffer& ab = mAcquiredBuffers.editItemAt(lockedIdx); + + ab.mSlot = b.mSlot; + ab.mGraphicBuffer = b.mGraphicBuffer; + ab.mLockedBufferId = getLockedBufferId(*nativeBuffer); mCurrentLockedBuffers++; @@ -208,60 +197,34 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { Mutex::Autolock _l(mMutex); - size_t lockedIdx = 0; - void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data); - for (; lockedIdx < static_cast<size_t>(mMaxLockedBuffers); lockedIdx++) { - if (bufPtr == mAcquiredBuffers[lockedIdx].mBufferPointer) break; - } + uintptr_t id = getLockedBufferId(nativeBuffer); + size_t lockedIdx = + (id != AcquiredBuffer::kUnusedId) ? findAcquiredBufferLocked(id) : mMaxLockedBuffers; if (lockedIdx == mMaxLockedBuffers) { CC_LOGE("%s: Can't find buffer to free", __FUNCTION__); return BAD_VALUE; } - return releaseAcquiredBufferLocked(lockedIdx); -} + AcquiredBuffer& ab = mAcquiredBuffers.editItemAt(lockedIdx); -status_t CpuConsumer::releaseAcquiredBufferLocked(size_t lockedIdx) { - status_t err; - int fd = -1; - - err = mAcquiredBuffers[lockedIdx].mGraphicBuffer->unlockAsync(&fd); + int fenceFd = -1; + status_t err = ab.mGraphicBuffer->unlockAsync(&fenceFd); if (err != OK) { CC_LOGE("%s: Unable to unlock graphic buffer %zd", __FUNCTION__, lockedIdx); return err; } - int buf = mAcquiredBuffers[lockedIdx].mSlot; - if (CC_LIKELY(fd != -1)) { - sp<Fence> fence(new Fence(fd)); - addReleaseFenceLocked( - mAcquiredBuffers[lockedIdx].mSlot, - mSlots[buf].mGraphicBuffer, - fence); - } - // release the buffer if it hasn't already been freed by the BufferQueue. - // This can happen, for example, when the producer of this buffer - // disconnected after this buffer was acquired. - if (CC_LIKELY(mAcquiredBuffers[lockedIdx].mGraphicBuffer == - mSlots[buf].mGraphicBuffer)) { - releaseBufferLocked( - buf, mAcquiredBuffers[lockedIdx].mGraphicBuffer, - EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); - } + sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); + addReleaseFenceLocked(ab.mSlot, ab.mGraphicBuffer, fence); + releaseBufferLocked(ab.mSlot, ab.mGraphicBuffer); - AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx); - ab.mSlot = BufferQueue::INVALID_BUFFER_SLOT; - ab.mBufferPointer = nullptr; - ab.mGraphicBuffer.clear(); + ab.reset(); mCurrentLockedBuffers--; - return OK; -} -void CpuConsumer::freeBufferLocked(int slotIndex) { - ConsumerBase::freeBufferLocked(slotIndex); + return OK; } } // namespace android diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp index f5cf1c4d5a..1757ec1cd3 100644 --- a/libs/gui/DisplayEventReceiver.cpp +++ b/libs/gui/DisplayEventReceiver.cpp @@ -34,9 +34,9 @@ namespace android { DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) { sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - if (sf != nullptr) { + if (sf != NULL) { mEventConnection = sf->createDisplayEventConnection(vsyncSource); - if (mEventConnection != nullptr) { + if (mEventConnection != NULL) { mDataChannel = std::make_unique<gui::BitTube>(); mEventConnection->stealReceiveChannel(mDataChannel.get()); } @@ -47,13 +47,13 @@ DisplayEventReceiver::~DisplayEventReceiver() { } status_t DisplayEventReceiver::initCheck() const { - if (mDataChannel != nullptr) + if (mDataChannel != NULL) return NO_ERROR; return NO_INIT; } int DisplayEventReceiver::getFd() const { - if (mDataChannel == nullptr) + if (mDataChannel == NULL) return NO_INIT; return mDataChannel->getFd(); @@ -63,7 +63,7 @@ status_t DisplayEventReceiver::setVsyncRate(uint32_t count) { if (int32_t(count) < 0) return BAD_VALUE; - if (mEventConnection != nullptr) { + if (mEventConnection != NULL) { mEventConnection->setVsyncRate(count); return NO_ERROR; } @@ -71,7 +71,7 @@ status_t DisplayEventReceiver::setVsyncRate(uint32_t count) { } status_t DisplayEventReceiver::requestNextVsync() { - if (mEventConnection != nullptr) { + if (mEventConnection != NULL) { mEventConnection->requestNextVsync(); return NO_ERROR; } diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp index fccca97f54..a379ad6306 100644 --- a/libs/gui/FrameTimestamps.cpp +++ b/libs/gui/FrameTimestamps.cpp @@ -628,7 +628,6 @@ FrameEventHistoryDelta& FrameEventHistoryDelta::operator=( ALOGE("FrameEventHistoryDelta assign clobbering history."); } mDeltas = std::move(src.mDeltas); - ALOGE_IF(src.mDeltas.empty(), "Source mDeltas not empty."); return *this; } diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 59e78cc6bf..885efec9b9 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -31,6 +31,8 @@ #include <hardware/hardware.h> +#include <math/mat4.h> + #include <gui/BufferItem.h> #include <gui/GLConsumer.h> #include <gui/ISurfaceComposer.h> @@ -75,33 +77,7 @@ static const struct { "_______________" }; -// Transform matrices -static float mtxIdentity[16] = { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1, -}; -static float mtxFlipH[16] = { - -1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 1, 0, 0, 1, -}; -static float mtxFlipV[16] = { - 1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, 1, 0, - 0, 1, 0, 1, -}; -static float mtxRot90[16] = { - 0, 1, 0, 0, - -1, 0, 0, 0, - 0, 0, 1, 0, - 1, 0, 0, 1, -}; - -static void mtxMul(float out[16], const float a[16], const float b[16]); +static const mat4 mtxIdentity; Mutex GLConsumer::sStaticInitLock; sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer; @@ -173,7 +149,7 @@ GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, { GLC_LOGV("GLConsumer"); - memcpy(mCurrentTransformMatrix, mtxIdentity, + memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); @@ -202,7 +178,7 @@ GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget, { GLC_LOGV("GLConsumer"); - memcpy(mCurrentTransformMatrix, mtxIdentity, + memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); @@ -315,7 +291,7 @@ status_t GLConsumer::releaseTexImage() { return err; } - if (mReleasedTexImage == nullptr) { + if (mReleasedTexImage == NULL) { mReleasedTexImage = new EglImage(getDebugTexImageBuffer()); } @@ -345,7 +321,7 @@ status_t GLConsumer::releaseTexImage() { sp<GraphicBuffer> GLConsumer::getDebugTexImageBuffer() { Mutex::Autolock _l(sStaticInitLock); - if (CC_UNLIKELY(sReleasedTexImageBuffer == nullptr)) { + if (CC_UNLIKELY(sReleasedTexImageBuffer == NULL)) { // The first time, create the debug texture in case the application // continues to use it. sp<GraphicBuffer> buffer = new GraphicBuffer( @@ -381,7 +357,7 @@ status_t GLConsumer::acquireBufferLocked(BufferItem *item, // If item->mGraphicBuffer is not null, this buffer has not been acquired // before, so any prior EglImage created is using a stale buffer. This // replaces any old EglImage with a new one (using the new buffer). - if (item->mGraphicBuffer != nullptr) { + if (item->mGraphicBuffer != NULL) { int slot = item->mSlot; mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer); } @@ -455,7 +431,7 @@ status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item, GLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, mCurrentTextureImage != NULL ? - mCurrentTextureImage->graphicBufferHandle() : nullptr, + mCurrentTextureImage->graphicBufferHandle() : 0, slot, mSlots[slot].mGraphicBuffer->handle); // Hang onto the pointer so that it isn't freed in the call to @@ -515,7 +491,7 @@ status_t GLConsumer::bindTextureImageLocked() { glBindTexture(mTexTarget, mTexName); if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && - mCurrentTextureImage == nullptr) { + mCurrentTextureImage == NULL) { GLC_LOGE("bindTextureImage: no currently-bound texture"); return NO_INIT; } @@ -679,7 +655,7 @@ status_t GLConsumer::attachToContext(uint32_t tex) { mTexName = tex; mAttached = true; - if (mCurrentTextureImage != nullptr) { + if (mCurrentTextureImage != NULL) { // This may wait for a buffer a second time. This is likely required if // this is a different context, since otherwise the wait could be skipped // by bouncing through another context. For the same context the extra @@ -700,7 +676,7 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { if (SyncFeatures::getInstance().useNativeFenceSync()) { EGLSyncKHR sync = eglCreateSyncKHR(dpy, - EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); + EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); if (sync == EGL_NO_SYNC_KHR) { GLC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError()); @@ -744,7 +720,7 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { // Create a fence for the outstanding accesses in the current // OpenGL ES context. - fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr); + fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL); if (fence == EGL_NO_SYNC_KHR) { GLC_LOGE("syncForReleaseLocked: error creating fence: %#x", eglGetError()); @@ -758,25 +734,6 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { return OK; } -bool GLConsumer::isExternalFormat(PixelFormat format) -{ - switch (format) { - // supported YUV formats - case HAL_PIXEL_FORMAT_YV12: - // Legacy/deprecated YUV formats - case HAL_PIXEL_FORMAT_YCbCr_422_SP: - case HAL_PIXEL_FORMAT_YCrCb_420_SP: - case HAL_PIXEL_FORMAT_YCbCr_422_I: - return true; - } - - // Any OEM format needs to be considered - if (format>=0x100 && format<=0x1FF) - return true; - - return false; -} - uint32_t GLConsumer::getCurrentTextureTarget() const { return mTexTarget; } @@ -795,11 +752,11 @@ void GLConsumer::setFilteringEnabled(bool enabled) { bool needsRecompute = mFilteringEnabled != enabled; mFilteringEnabled = enabled; - if (needsRecompute && mCurrentTextureImage==nullptr) { + if (needsRecompute && mCurrentTextureImage==NULL) { GLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL"); } - if (needsRecompute && mCurrentTextureImage != nullptr) { + if (needsRecompute && mCurrentTextureImage != NULL) { computeCurrentTransformMatrixLocked(); } } @@ -820,34 +777,37 @@ void GLConsumer::computeCurrentTransformMatrixLocked() { void GLConsumer::computeTransformMatrix(float outTransform[16], const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform, bool filtering) { - - float xform[16]; - for (int i = 0; i < 16; i++) { - xform[i] = mtxIdentity[i]; - } + // Transform matrices + static const mat4 mtxFlipH( + -1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 1, 0, 0, 1 + ); + static const mat4 mtxFlipV( + 1, 0, 0, 0, + 0, -1, 0, 0, + 0, 0, 1, 0, + 0, 1, 0, 1 + ); + static const mat4 mtxRot90( + 0, 1, 0, 0, + -1, 0, 0, 0, + 0, 0, 1, 0, + 1, 0, 0, 1 + ); + + mat4 xform; if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { - float result[16]; - mtxMul(result, xform, mtxFlipH); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } + xform *= mtxFlipH; } if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { - float result[16]; - mtxMul(result, xform, mtxFlipV); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } + xform *= mtxFlipV; } if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { - float result[16]; - mtxMul(result, xform, mtxRot90); - for (int i = 0; i < 16; i++) { - xform[i] = result[i]; - } + xform *= mtxRot90; } - float mtxBeforeFlipV[16]; if (!cropRect.isEmpty()) { float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f; float bufferWidth = buf->getWidth(); @@ -893,25 +853,63 @@ void GLConsumer::computeTransformMatrix(float outTransform[16], sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / bufferHeight; } - float crop[16] = { + + mat4 crop( sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, - tx, ty, 0, 1, - }; - - mtxMul(mtxBeforeFlipV, crop, xform); - } else { - for (int i = 0; i < 16; i++) { - mtxBeforeFlipV[i] = xform[i]; - } + tx, ty, 0, 1 + ); + xform = crop * xform; } // SurfaceFlinger expects the top of its window textures to be at a Y // coordinate of 0, so GLConsumer must behave the same way. We don't // want to expose this to applications, however, so we must add an // additional vertical flip to the transform after all the other transforms. - mtxMul(outTransform, mtxFlipV, mtxBeforeFlipV); + xform = mtxFlipV * xform; + + memcpy(outTransform, xform.asArray(), sizeof(xform)); +} + +Rect GLConsumer::scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight) { + Rect outCrop = crop; + + uint32_t newWidth = static_cast<uint32_t>(crop.width()); + uint32_t newHeight = static_cast<uint32_t>(crop.height()); + + if (newWidth * bufferHeight > newHeight * bufferWidth) { + newWidth = newHeight * bufferWidth / bufferHeight; + ALOGV("too wide: newWidth = %d", newWidth); + } else if (newWidth * bufferHeight < newHeight * bufferWidth) { + newHeight = newWidth * bufferHeight / bufferWidth; + ALOGV("too tall: newHeight = %d", newHeight); + } + + uint32_t currentWidth = static_cast<uint32_t>(crop.width()); + uint32_t currentHeight = static_cast<uint32_t>(crop.height()); + + // The crop is too wide + if (newWidth < currentWidth) { + uint32_t dw = currentWidth - newWidth; + auto halfdw = dw / 2; + outCrop.left += halfdw; + // Not halfdw because it would subtract 1 too few when dw is odd + outCrop.right -= (dw - halfdw); + // The crop is too tall + } else if (newHeight < currentHeight) { + uint32_t dh = currentHeight - newHeight; + auto halfdh = dh / 2; + outCrop.top += halfdh; + // Not halfdh because it would subtract 1 too few when dh is odd + outCrop.bottom -= (dh - halfdh); + } + + ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]", + outCrop.left, outCrop.top, + outCrop.right,outCrop.bottom); + + return outCrop; } nsecs_t GLConsumer::getTimestamp() { @@ -940,50 +938,14 @@ sp<GraphicBuffer> GLConsumer::getCurrentBuffer(int* outSlot) const { } return (mCurrentTextureImage == nullptr) ? - nullptr : mCurrentTextureImage->graphicBuffer(); + NULL : mCurrentTextureImage->graphicBuffer(); } Rect GLConsumer::getCurrentCrop() const { Mutex::Autolock lock(mMutex); - - Rect outCrop = mCurrentCrop; - if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) { - uint32_t newWidth = static_cast<uint32_t>(mCurrentCrop.width()); - uint32_t newHeight = static_cast<uint32_t>(mCurrentCrop.height()); - - if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) { - newWidth = newHeight * mDefaultWidth / mDefaultHeight; - GLC_LOGV("too wide: newWidth = %d", newWidth); - } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) { - newHeight = newWidth * mDefaultHeight / mDefaultWidth; - GLC_LOGV("too tall: newHeight = %d", newHeight); - } - - uint32_t currentWidth = static_cast<uint32_t>(mCurrentCrop.width()); - uint32_t currentHeight = static_cast<uint32_t>(mCurrentCrop.height()); - - // The crop is too wide - if (newWidth < currentWidth) { - uint32_t dw = currentWidth - newWidth; - auto halfdw = dw / 2; - outCrop.left += halfdw; - // Not halfdw because it would subtract 1 too few when dw is odd - outCrop.right -= (dw - halfdw); - // The crop is too tall - } else if (newHeight < currentHeight) { - uint32_t dh = currentHeight - newHeight; - auto halfdh = dh / 2; - outCrop.top += halfdh; - // Not halfdh because it would subtract 1 too few when dh is odd - outCrop.bottom -= (dh - halfdh); - } - - GLC_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]", - outCrop.left, outCrop.top, - outCrop.right,outCrop.bottom); - } - - return outCrop; + return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) + ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight) + : mCurrentCrop; } uint32_t GLConsumer::getCurrentTransform() const { @@ -1006,11 +968,6 @@ std::shared_ptr<FenceTime> GLConsumer::getCurrentFenceTime() const { return mCurrentFenceTime; } -status_t GLConsumer::doGLFenceWait() const { - Mutex::Autolock lock(mMutex); - return doGLFenceWaitLocked(); -} - status_t GLConsumer::doGLFenceWaitLocked() const { EGLDisplay dpy = eglGetCurrentDisplay(); @@ -1027,7 +984,8 @@ status_t GLConsumer::doGLFenceWaitLocked() const { } if (mCurrentFence->isValid()) { - if (SyncFeatures::getInstance().useWaitSync()) { + if (SyncFeatures::getInstance().useWaitSync() && + SyncFeatures::getInstance().useNativeFenceSync()) { // Create an EGLSyncKHR from the current fence. int fenceFd = mCurrentFence->dup(); if (fenceFd == -1) { @@ -1086,61 +1044,8 @@ void GLConsumer::abandonLocked() { ConsumerBase::abandonLocked(); } -void GLConsumer::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - if (mAbandoned) { - GLC_LOGE("setName: GLConsumer is abandoned!"); - return; - } - mName = name; - mConsumer->setConsumerName(name); -} - -status_t GLConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setDefaultBufferFormat: GLConsumer is abandoned!"); - return NO_INIT; - } - return mConsumer->setDefaultBufferFormat(defaultFormat); -} - -status_t GLConsumer::setDefaultBufferDataSpace( - android_dataspace defaultDataSpace) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setDefaultBufferDataSpace: GLConsumer is abandoned!"); - return NO_INIT; - } - return mConsumer->setDefaultBufferDataSpace(defaultDataSpace); -} - status_t GLConsumer::setConsumerUsageBits(uint64_t usage) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setConsumerUsageBits: GLConsumer is abandoned!"); - return NO_INIT; - } - usage |= DEFAULT_USAGE_FLAGS; - return mConsumer->setConsumerUsageBits(usage); -} - -status_t GLConsumer::setTransformHint(uint32_t hint) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setTransformHint: GLConsumer is abandoned!"); - return NO_INIT; - } - return mConsumer->setTransformHint(hint); -} - -status_t GLConsumer::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - GLC_LOGE("setMaxAcquiredBufferCount: GLConsumer is abandoned!"); - return NO_INIT; - } - return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers); + return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS); } void GLConsumer::dumpLocked(String8& result, const char* prefix) const @@ -1155,28 +1060,6 @@ void GLConsumer::dumpLocked(String8& result, const char* prefix) const ConsumerBase::dumpLocked(result, prefix); } -static void mtxMul(float out[16], const float a[16], const float b[16]) { - out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3]; - out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3]; - out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3]; - out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3]; - - out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7]; - out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7]; - out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7]; - out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7]; - - out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11]; - out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11]; - out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11]; - out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11]; - - out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15]; - out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15]; - out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15]; - out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15]; -} - GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) : mGraphicBuffer(graphicBuffer), mEglImage(EGL_NO_IMAGE_KHR), @@ -1267,7 +1150,7 @@ EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy, attrs[3] = attrs[11]; attrs[4] = EGL_NONE; } - eglInitialize(dpy, nullptr, nullptr); + eglInitialize(dpy, 0, 0); EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs); if (image == EGL_NO_IMAGE_KHR) { diff --git a/libs/gui/HdrMetadata.cpp b/libs/gui/HdrMetadata.cpp new file mode 100644 index 0000000000..b715e431d5 --- /dev/null +++ b/libs/gui/HdrMetadata.cpp @@ -0,0 +1,97 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gui/HdrMetadata.h> + +namespace android { + +size_t HdrMetadata::getFlattenedSize() const { + size_t size = sizeof(validTypes); + if (validTypes & SMPTE2086) { + size += sizeof(smpte2086); + } + if (validTypes & CTA861_3) { + size += sizeof(cta8613); + } + return size; +} + +status_t HdrMetadata::flatten(void* buffer, size_t size) const { + if (size < getFlattenedSize()) { + return NO_MEMORY; + } + + FlattenableUtils::write(buffer, size, validTypes); + if (validTypes & SMPTE2086) { + FlattenableUtils::write(buffer, size, smpte2086); + } + if (validTypes & CTA861_3) { + FlattenableUtils::write(buffer, size, cta8613); + } + + return NO_ERROR; +} + +status_t HdrMetadata::unflatten(void const* buffer, size_t size) { + if (size < sizeof(validTypes)) { + return NO_MEMORY; + } + FlattenableUtils::read(buffer, size, validTypes); + if (validTypes & SMPTE2086) { + if (size < sizeof(smpte2086)) { + return NO_MEMORY; + } + FlattenableUtils::read(buffer, size, smpte2086); + } + if (validTypes & CTA861_3) { + if (size < sizeof(cta8613)) { + return NO_MEMORY; + } + FlattenableUtils::read(buffer, size, cta8613); + } + + return NO_ERROR; +} + +bool HdrMetadata::operator==(const HdrMetadata& rhs) const { + if (validTypes != rhs.validTypes) return false; + + if ((validTypes & SMPTE2086) == SMPTE2086) { + if (smpte2086.displayPrimaryRed.x != rhs.smpte2086.displayPrimaryRed.x || + smpte2086.displayPrimaryRed.y != rhs.smpte2086.displayPrimaryRed.y || + smpte2086.displayPrimaryGreen.x != rhs.smpte2086.displayPrimaryGreen.x || + smpte2086.displayPrimaryGreen.y != rhs.smpte2086.displayPrimaryGreen.y || + smpte2086.displayPrimaryBlue.x != rhs.smpte2086.displayPrimaryBlue.x || + smpte2086.displayPrimaryBlue.y != rhs.smpte2086.displayPrimaryBlue.y || + smpte2086.whitePoint.x != rhs.smpte2086.whitePoint.x || + smpte2086.whitePoint.y != rhs.smpte2086.whitePoint.y || + smpte2086.maxLuminance != rhs.smpte2086.maxLuminance || + smpte2086.minLuminance != rhs.smpte2086.minLuminance) { + return false; + } + } + + if ((validTypes & CTA861_3) == CTA861_3) { + if (cta8613.maxFrameAverageLightLevel != rhs.cta8613.maxFrameAverageLightLevel || + cta8613.maxContentLightLevel != rhs.cta8613.maxContentLightLevel) { + return false; + } + } + + return true; +} + +} // namespace android diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 23e9ddc014..0749fde1ad 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -27,6 +27,9 @@ #include <binder/Parcel.h> #include <binder/IInterface.h> +#ifndef NO_BUFFERHUB +#include <gui/BufferHubProducer.h> +#endif #include <gui/BufferQueueDefs.h> #include <gui/IGraphicBufferProducer.h> #include <gui/IProducerListener.h> @@ -187,10 +190,10 @@ public: virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) { - if (outBuffer == nullptr) { + if (outBuffer == NULL) { ALOGE("detachNextBuffer: outBuffer must not be NULL"); return BAD_VALUE; - } else if (outFence == nullptr) { + } else if (outFence == NULL) { ALOGE("detachNextBuffer: outFence must not be NULL"); return BAD_VALUE; } @@ -298,7 +301,7 @@ public: int api, bool producerControlledByApp, QueueBufferOutput* output) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); - if (listener != nullptr) { + if (listener != NULL) { data.writeInt32(1); data.writeStrongBinder(IInterface::asBinder(listener)); } else { @@ -653,6 +656,79 @@ IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer, // ---------------------------------------------------------------------- +status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) { + status_t res = OK; + res = parcel->writeUint32(USE_BUFFER_QUEUE); + if (res != NO_ERROR) { + ALOGE("exportToParcel: Cannot write magic, res=%d.", res); + return res; + } + + return parcel->writeStrongBinder(IInterface::asBinder(this)); +} + +/* static */ +status_t IGraphicBufferProducer::exportToParcel(const sp<IGraphicBufferProducer>& producer, + Parcel* parcel) { + if (parcel == nullptr) { + ALOGE("exportToParcel: Invalid parcel object."); + return BAD_VALUE; + } + + if (producer == nullptr) { + status_t res = OK; + res = parcel->writeUint32(IGraphicBufferProducer::USE_BUFFER_QUEUE); + if (res != NO_ERROR) return res; + return parcel->writeStrongBinder(nullptr); + } else { + return producer->exportToParcel(parcel); + } +} + +/* static */ +sp<IGraphicBufferProducer> IGraphicBufferProducer::createFromParcel(const Parcel* parcel) { + uint32_t outMagic = 0; + status_t res = NO_ERROR; + + res = parcel->readUint32(&outMagic); + if (res != NO_ERROR) { + ALOGE("createFromParcel: Failed to read magic, error=%d.", res); + return nullptr; + } + + switch (outMagic) { + case USE_BUFFER_QUEUE: { + sp<IBinder> binder; + res = parcel->readNullableStrongBinder(&binder); + if (res != NO_ERROR) { + ALOGE("createFromParcel: Can't read strong binder."); + return nullptr; + } + return interface_cast<IGraphicBufferProducer>(binder); + } + case USE_BUFFER_HUB: { + ALOGE("createFromParcel: BufferHub not implemented."); +#ifndef NO_BUFFERHUB + dvr::ProducerQueueParcelable producerParcelable; + res = producerParcelable.readFromParcel(parcel); + if (res != NO_ERROR) { + ALOGE("createFromParcel: Failed to read from parcel, error=%d", res); + return nullptr; + } + return BufferHubProducer::Create(std::move(producerParcelable)); +#else + return nullptr; +#endif + } + default: { + ALOGE("createFromParcel: Unexpected mgaic: 0x%x.", outMagic); + return nullptr; + } + } +} + +// ---------------------------------------------------------------------------- + status_t BnGraphicBufferProducer::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { @@ -662,8 +738,8 @@ status_t BnGraphicBufferProducer::onTransact( int bufferIdx = data.readInt32(); sp<GraphicBuffer> buffer; int result = requestBuffer(bufferIdx, &buffer); - reply->writeInt32(buffer != nullptr); - if (buffer != nullptr) { + reply->writeInt32(buffer != 0); + if (buffer != 0) { reply->write(*buffer); } reply->writeInt32(result); @@ -721,12 +797,12 @@ status_t BnGraphicBufferProducer::onTransact( int32_t result = detachNextBuffer(&buffer, &fence); reply->writeInt32(result); if (result == NO_ERROR) { - reply->writeInt32(buffer != nullptr); - if (buffer != nullptr) { + reply->writeInt32(buffer != NULL); + if (buffer != NULL) { reply->write(*buffer); } - reply->writeInt32(fence != nullptr); - if (fence != nullptr) { + reply->writeInt32(fence != NULL); + if (fence != NULL) { reply->write(*fence); } } @@ -951,7 +1027,8 @@ constexpr size_t IGraphicBufferProducer::QueueBufferInput::minFlattenedSize() { size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const { return minFlattenedSize() + fence->getFlattenedSize() + - surfaceDamage.getFlattenedSize(); + surfaceDamage.getFlattenedSize() + + hdrMetadata.getFlattenedSize(); } size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const { @@ -978,7 +1055,12 @@ status_t IGraphicBufferProducer::QueueBufferInput::flatten( if (result != NO_ERROR) { return result; } - return surfaceDamage.flatten(buffer, size); + result = surfaceDamage.flatten(buffer, size); + if (result != NO_ERROR) { + return result; + } + FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize()); + return hdrMetadata.flatten(buffer, size); } status_t IGraphicBufferProducer::QueueBufferInput::unflatten( @@ -1002,7 +1084,12 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( if (result != NO_ERROR) { return result; } - return surfaceDamage.unflatten(buffer, size); + result = surfaceDamage.unflatten(buffer, size); + if (result != NO_ERROR) { + return result; + } + FlattenableUtils::advance(buffer, size, surfaceDamage.getFlattenedSize()); + return hdrMetadata.unflatten(buffer, size); } // ---------------------------------------------------------------------------- diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 8e7f814313..e22bc708c9 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -29,8 +29,7 @@ #include <gui/ISurfaceComposer.h> #include <gui/ISurfaceComposerClient.h> #include <gui/LayerDebugInfo.h> - -#include <private/gui/LayerState.h> +#include <gui/LayerState.h> #include <system/graphics.h> @@ -44,6 +43,8 @@ namespace android { +using ui::ColorMode; + class BpSurfaceComposer : public BpInterface<ISurfaceComposer> { public: @@ -101,17 +102,13 @@ public: remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply); } - virtual status_t captureScreen(const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, - ISurfaceComposer::Rotation rotation) - { + virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, + ISurfaceComposer::Rotation rotation) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); - data.writeStrongBinder(IInterface::asBinder(producer)); data.write(sourceCrop); data.writeUint32(reqWidth); data.writeUint32(reqHeight); @@ -119,8 +116,46 @@ public: data.writeInt32(maxLayerZ); data.writeInt32(static_cast<int32_t>(useIdentityTransform)); data.writeInt32(static_cast<int32_t>(rotation)); - remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); - return reply.readInt32(); + status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); + + if (err != NO_ERROR) { + return err; + } + + err = reply.readInt32(); + if (err != NO_ERROR) { + return err; + } + + *outBuffer = new GraphicBuffer(); + reply.read(**outBuffer); + return err; + } + + virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder, + sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop, + float frameScale, bool childrenOnly) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeStrongBinder(layerHandleBinder); + data.write(sourceCrop); + data.writeFloat(frameScale); + data.writeBool(childrenOnly); + status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply); + + if (err != NO_ERROR) { + return err; + } + + err = reply.readInt32(); + if (err != NO_ERROR) { + return err; + } + + *outBuffer = new GraphicBuffer(); + reply.read(**outBuffer); + + return err; } virtual bool authenticateSurfaceTexture( @@ -317,7 +352,7 @@ public: } virtual status_t getDisplayColorModes(const sp<IBinder>& display, - Vector<android_color_mode_t>* outColorModes) { + Vector<ColorMode>* outColorModes) { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -340,34 +375,34 @@ public: outColorModes->clear(); outColorModes->resize(numModes); for (size_t i = 0; i < numModes; ++i) { - outColorModes->replaceAt(static_cast<android_color_mode_t>(reply.readInt32()), i); + outColorModes->replaceAt(static_cast<ColorMode>(reply.readInt32()), i); } } return result; } - virtual android_color_mode_t getActiveColorMode(const sp<IBinder>& display) { + virtual ColorMode getActiveColorMode(const sp<IBinder>& display) { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { ALOGE("getActiveColorMode failed to writeInterfaceToken: %d", result); - return static_cast<android_color_mode_t>(result); + return static_cast<ColorMode>(result); } result = data.writeStrongBinder(display); if (result != NO_ERROR) { ALOGE("getActiveColorMode failed to writeStrongBinder: %d", result); - return static_cast<android_color_mode_t>(result); + return static_cast<ColorMode>(result); } result = remote()->transact(BnSurfaceComposer::GET_ACTIVE_COLOR_MODE, data, &reply); if (result != NO_ERROR) { ALOGE("getActiveColorMode failed to transact: %d", result); - return static_cast<android_color_mode_t>(result); + return static_cast<ColorMode>(result); } - return static_cast<android_color_mode_t>(reply.readInt32()); + return static_cast<ColorMode>(reply.readInt32()); } virtual status_t setActiveColorMode(const sp<IBinder>& display, - android_color_mode_t colorMode) { + ColorMode colorMode) { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -379,7 +414,7 @@ public: ALOGE("setActiveColorMode failed to writeStrongBinder: %d", result); return result; } - result = data.writeInt32(colorMode); + result = data.writeInt32(static_cast<int32_t>(colorMode)); if (result != NO_ERROR) { ALOGE("setActiveColorMode failed to writeInt32: %d", result); return result; @@ -571,8 +606,7 @@ status_t BnSurfaceComposer::onTransact( case CAPTURE_SCREEN: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp<IBinder> display = data.readStrongBinder(); - sp<IGraphicBufferProducer> producer = - interface_cast<IGraphicBufferProducer>(data.readStrongBinder()); + sp<GraphicBuffer> outBuffer; Rect sourceCrop(Rect::EMPTY_RECT); data.read(sourceCrop); uint32_t reqWidth = data.readUint32(); @@ -582,11 +616,30 @@ status_t BnSurfaceComposer::onTransact( bool useIdentityTransform = static_cast<bool>(data.readInt32()); int32_t rotation = data.readInt32(); - status_t res = captureScreen(display, producer, - sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ, - useIdentityTransform, - static_cast<ISurfaceComposer::Rotation>(rotation)); + status_t res = captureScreen(display, &outBuffer, sourceCrop, reqWidth, reqHeight, + minLayerZ, maxLayerZ, useIdentityTransform, + static_cast<ISurfaceComposer::Rotation>(rotation)); reply->writeInt32(res); + if (res == NO_ERROR) { + reply->write(*outBuffer); + } + return NO_ERROR; + } + case CAPTURE_LAYERS: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IBinder> layerHandleBinder = data.readStrongBinder(); + sp<GraphicBuffer> outBuffer; + Rect sourceCrop(Rect::EMPTY_RECT); + data.read(sourceCrop); + float frameScale = data.readFloat(); + bool childrenOnly = data.readBool(); + + status_t res = captureLayers(layerHandleBinder, &outBuffer, sourceCrop, frameScale, + childrenOnly); + reply->writeInt32(res); + if (res == NO_ERROR) { + reply->write(*outBuffer); + } return NO_ERROR; } case AUTHENTICATE_SURFACE: { @@ -688,7 +741,7 @@ status_t BnSurfaceComposer::onTransact( } case GET_DISPLAY_COLOR_MODES: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - Vector<android_color_mode_t> colorModes; + Vector<ColorMode> colorModes; sp<IBinder> display = nullptr; status_t result = data.readStrongBinder(&display); if (result != NO_ERROR) { @@ -700,7 +753,7 @@ status_t BnSurfaceComposer::onTransact( if (result == NO_ERROR) { reply->writeUint32(static_cast<uint32_t>(colorModes.size())); for (size_t i = 0; i < colorModes.size(); ++i) { - reply->writeInt32(colorModes[i]); + reply->writeInt32(static_cast<int32_t>(colorModes[i])); } } return NO_ERROR; @@ -713,7 +766,7 @@ status_t BnSurfaceComposer::onTransact( ALOGE("getActiveColorMode failed to readStrongBinder: %d", result); return result; } - android_color_mode_t colorMode = getActiveColorMode(display); + ColorMode colorMode = getActiveColorMode(display); result = reply->writeInt32(static_cast<int32_t>(colorMode)); return result; } @@ -732,7 +785,7 @@ status_t BnSurfaceComposer::onTransact( return result; } result = setActiveColorMode(display, - static_cast<android_color_mode_t>(colorModeInt)); + static_cast<ColorMode>(colorModeInt)); result = reply->writeInt32(result); return result; } diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp index 679f44b57b..a6890eeb19 100644 --- a/libs/gui/ISurfaceComposerClient.cpp +++ b/libs/gui/ISurfaceComposerClient.cpp @@ -47,8 +47,8 @@ public: ~BpSurfaceComposerClient() override; status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format, - uint32_t flags, const sp<IBinder>& parent, uint32_t windowType, - uint32_t ownerUid, sp<IBinder>* handle, + uint32_t flags, const sp<IBinder>& parent, int32_t windowType, + int32_t ownerUid, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) override { return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CREATE_SURFACE, name, width, height, diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp index 57ddde075a..d3dc16d30e 100644 --- a/libs/gui/LayerDebugInfo.cpp +++ b/libs/gui/LayerDebugInfo.cpp @@ -43,7 +43,10 @@ status_t LayerDebugInfo::writeToParcel(Parcel* parcel) const { RETURN_ON_ERROR(parcel->writeInt32(mHeight)); RETURN_ON_ERROR(parcel->write(mCrop)); RETURN_ON_ERROR(parcel->write(mFinalCrop)); - RETURN_ON_ERROR(parcel->writeFloat(mAlpha)); + RETURN_ON_ERROR(parcel->writeFloat(mColor.r)); + RETURN_ON_ERROR(parcel->writeFloat(mColor.g)); + RETURN_ON_ERROR(parcel->writeFloat(mColor.b)); + RETURN_ON_ERROR(parcel->writeFloat(mColor.a)); RETURN_ON_ERROR(parcel->writeUint32(mFlags)); RETURN_ON_ERROR(parcel->writeInt32(mPixelFormat)); RETURN_ON_ERROR(parcel->writeUint32(static_cast<uint32_t>(mDataSpace))); @@ -79,7 +82,14 @@ status_t LayerDebugInfo::readFromParcel(const Parcel* parcel) { RETURN_ON_ERROR(parcel->readInt32(&mHeight)); RETURN_ON_ERROR(parcel->read(mCrop)); RETURN_ON_ERROR(parcel->read(mFinalCrop)); - RETURN_ON_ERROR(parcel->readFloat(&mAlpha)); + mColor.r = parcel->readFloat(); + RETURN_ON_ERROR(parcel->errorCheck()); + mColor.g = parcel->readFloat(); + RETURN_ON_ERROR(parcel->errorCheck()); + mColor.b = parcel->readFloat(); + RETURN_ON_ERROR(parcel->errorCheck()); + mColor.a = parcel->readFloat(); + RETURN_ON_ERROR(parcel->errorCheck()); RETURN_ON_ERROR(parcel->readUint32(&mFlags)); RETURN_ON_ERROR(parcel->readInt32(&mPixelFormat)); // \todo [2017-07-25 kraita]: Static casting mDataSpace pointer to an uint32 does work. Better ways? @@ -116,8 +126,10 @@ std::string to_string(const LayerDebugInfo& info) { result.appendFormat("isOpaque=%1d, invalidate=%1d, ", info.mIsOpaque, info.mContentDirty); result.appendFormat("dataspace=%s, ", dataspaceDetails(info.mDataSpace).c_str()); result.appendFormat("pixelformat=%s, ", decodePixelFormat(info.mPixelFormat).c_str()); - result.appendFormat("alpha=%.3f, flags=0x%08x, ", - static_cast<double>(info.mAlpha), info.mFlags); + result.appendFormat("color=(%.3f,%.3f,%.3f,%.3f), flags=0x%08x, ", + static_cast<double>(info.mColor.r), static_cast<double>(info.mColor.g), + static_cast<double>(info.mColor.b), static_cast<double>(info.mColor.a), + info.mFlags); result.appendFormat("tr=[%.2f, %.2f][%.2f, %.2f]", static_cast<double>(info.mMatrix[0][0]), static_cast<double>(info.mMatrix[0][1]), static_cast<double>(info.mMatrix[1][0]), static_cast<double>(info.mMatrix[1][1])); diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 9b06e63610..01acc2de20 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -18,7 +18,7 @@ #include <binder/Parcel.h> #include <gui/ISurfaceComposerClient.h> #include <gui/IGraphicBufferProducer.h> -#include <private/gui/LayerState.h> +#include <gui/LayerState.h> namespace android { @@ -45,6 +45,10 @@ status_t layer_state_t::write(Parcel& output) const output.writeInt32(overrideScalingMode); output.writeStrongBinder(IInterface::asBinder(barrierGbp)); output.writeStrongBinder(relativeLayerHandle); + output.writeStrongBinder(parentHandleForChild); + output.writeFloat(color.r); + output.writeFloat(color.g); + output.writeFloat(color.b); output.write(transparentRegion); return NO_ERROR; } @@ -77,6 +81,10 @@ status_t layer_state_t::read(const Parcel& input) barrierGbp = interface_cast<IGraphicBufferProducer>(input.readStrongBinder()); relativeLayerHandle = input.readStrongBinder(); + parentHandleForChild = input.readStrongBinder(); + color.r = input.readFloat(); + color.g = input.readFloat(); + color.b = input.readFloat(); input.read(transparentRegion); return NO_ERROR; } @@ -128,5 +136,104 @@ status_t DisplayState::read(const Parcel& input) { return NO_ERROR; } +void DisplayState::merge(const DisplayState& other) { + if (other.what & eSurfaceChanged) { + what |= eSurfaceChanged; + surface = other.surface; + } + if (other.what & eLayerStackChanged) { + what |= eLayerStackChanged; + layerStack = other.layerStack; + } + if (other.what & eDisplayProjectionChanged) { + what |= eDisplayProjectionChanged; + orientation = other.orientation; + viewport = other.viewport; + frame = other.frame; + } + if (other.what & eDisplaySizeChanged) { + what |= eDisplaySizeChanged; + width = other.width; + height = other.height; + } +} + +void layer_state_t::merge(const layer_state_t& other) { + if (other.what & ePositionChanged) { + what |= ePositionChanged; + x = other.x; + y = other.y; + } + if (other.what & eLayerChanged) { + what |= eLayerChanged; + z = other.z; + } + if (other.what & eSizeChanged) { + what |= eSizeChanged; + w = other.w; + h = other.h; + } + if (other.what & eAlphaChanged) { + what |= eAlphaChanged; + alpha = other.alpha; + } + if (other.what & eMatrixChanged) { + what |= eMatrixChanged; + matrix = other.matrix; + } + if (other.what & eTransparentRegionChanged) { + what |= eTransparentRegionChanged; + transparentRegion = other.transparentRegion; + } + if (other.what & eFlagsChanged) { + what |= eFlagsChanged; + flags = other.flags; + mask = other.mask; + } + if (other.what & eLayerStackChanged) { + what |= eLayerStackChanged; + layerStack = other.layerStack; + } + if (other.what & eCropChanged) { + what |= eCropChanged; + crop = other.crop; + } + if (other.what & eDeferTransaction) { + what |= eDeferTransaction; + barrierHandle = other.barrierHandle; + barrierGbp = other.barrierGbp; + frameNumber = other.frameNumber; + } + if (other.what & eFinalCropChanged) { + what |= eFinalCropChanged; + finalCrop = other.finalCrop; + } + if (other.what & eOverrideScalingModeChanged) { + what |= eOverrideScalingModeChanged; + overrideScalingMode = other.overrideScalingMode; + } + if (other.what & eGeometryAppliesWithResize) { + what |= eGeometryAppliesWithResize; + } + if (other.what & eReparentChildren) { + what |= eReparentChildren; + reparentHandle = other.reparentHandle; + } + if (other.what & eDetachChildren) { + what |= eDetachChildren; + } + if (other.what & eRelativeLayerChanged) { + what |= eRelativeLayerChanged; + z = other.z; + relativeLayerHandle = other.relativeLayerHandle; + } + if (other.what & eReparent) { + what |= eReparent; + parentHandleForChild = other.parentHandleForChild; + } + if (other.what & eDestroySurface) { + what |= eDestroySurface; + } +} }; // namespace android diff --git a/libs/gui/StreamSplitter.cpp b/libs/gui/StreamSplitter.cpp index 2f8e104ea0..52c906775e 100644 --- a/libs/gui/StreamSplitter.cpp +++ b/libs/gui/StreamSplitter.cpp @@ -38,11 +38,11 @@ namespace android { status_t StreamSplitter::createSplitter( const sp<IGraphicBufferConsumer>& inputQueue, sp<StreamSplitter>* outSplitter) { - if (inputQueue == nullptr) { + if (inputQueue == NULL) { ALOGE("createSplitter: inputQueue must not be NULL"); return BAD_VALUE; } - if (outSplitter == nullptr) { + if (outSplitter == NULL) { ALOGE("createSplitter: outSplitter must not be NULL"); return BAD_VALUE; } @@ -74,7 +74,7 @@ StreamSplitter::~StreamSplitter() { status_t StreamSplitter::addOutput( const sp<IGraphicBufferProducer>& outputQueue) { - if (outputQueue == nullptr) { + if (outputQueue == NULL) { ALOGE("addOutput: outputQueue must not be NULL"); return BAD_VALUE; } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e55e6e415a..339bd0fa4e 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -44,6 +44,9 @@ namespace android { +using ui::ColorMode; +using ui::Dataspace; + Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp) : mGraphicBufferProducer(bufferProducer), mCrop(Rect::EMPTY_RECT), @@ -78,7 +81,7 @@ Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controll mReqFormat = 0; mReqUsage = 0; mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; - mDataSpace = HAL_DATASPACE_UNKNOWN; + mDataSpace = Dataspace::UNKNOWN; mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mTransform = 0; mStickyTransform = 0; @@ -153,7 +156,7 @@ status_t Surface::getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration) { ATRACE_CALL(); DisplayStatInfo stats; - status_t result = composerService()->getDisplayStats(nullptr, &stats); + status_t result = composerService()->getDisplayStats(NULL, &stats); if (result != NO_ERROR) { return result; } @@ -326,7 +329,7 @@ status_t Surface::getWideColorSupport(bool* supported) { sp<IBinder> display( composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - Vector<android_color_mode_t> colorModes; + Vector<ColorMode> colorModes; status_t err = composerService()->getDisplayColorModes(display, &colorModes); @@ -338,11 +341,11 @@ status_t Surface::getWideColorSupport(bool* supported) { &ISurfaceFlingerConfigs::hasWideColorDisplay>(false); *supported = false; - for (android_color_mode_t colorMode : colorModes) { + for (ColorMode colorMode : colorModes) { switch (colorMode) { - case HAL_COLOR_MODE_DISPLAY_P3: - case HAL_COLOR_MODE_ADOBE_RGB: - case HAL_COLOR_MODE_DCI_P3: + case ColorMode::DISPLAY_P3: + case ColorMode::ADOBE_RGB: + case ColorMode::DCI_P3: if (wideColorBoardConfig) { *supported = true; } @@ -494,7 +497,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot != BufferItem::INVALID_BUFFER_SLOT) { sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer); - if (gbuf != nullptr) { + if (gbuf != NULL) { *buffer = gbuf.get(); *fenceFd = -1; return OK; @@ -534,7 +537,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { sp<GraphicBuffer>& gbuf(mSlots[buf].buffer); // this should never happen - ALOGE_IF(fence == nullptr, "Surface::dequeueBuffer: received null Fence! buf=%d", buf); + ALOGE_IF(fence == NULL, "Surface::dequeueBuffer: received null Fence! buf=%d", buf); if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) { freeAllBuffers(); @@ -612,7 +615,7 @@ int Surface::cancelBuffer(android_native_buffer_t* buffer, int Surface::getSlotFromBufferLocked( android_native_buffer_t* buffer) const { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].buffer != nullptr && + if (mSlots[i].buffer != NULL && mSlots[i].buffer->handle == buffer->handle) { return i; } @@ -664,8 +667,12 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); IGraphicBufferProducer::QueueBufferOutput output; IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp, - mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform, - fence, mStickyTransform, mEnableFrameTimestamps); + static_cast<android_dataspace>(mDataSpace), crop, mScalingMode, + mTransform ^ mStickyTransform, fence, mStickyTransform, + mEnableFrameTimestamps); + + // we should send HDR metadata as needed if this becomes a bottleneck + input.setHdrMetadata(mHdrMetadata); if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) { input.setSurfaceDamage(Region::INVALID_REGION); @@ -878,6 +885,10 @@ int Surface::query(int what, int* value) const { *value = mGraphicBufferProducer != nullptr ? 1 : 0; return NO_ERROR; } + case NATIVE_WINDOW_DATASPACE: { + *value = static_cast<int>(mDataSpace); + return NO_ERROR; + } } } return mGraphicBufferProducer->query(what, value); @@ -944,6 +955,12 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_BUFFERS_DATASPACE: res = dispatchSetBuffersDataSpace(args); break; + case NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA: + res = dispatchSetBuffersSmpte2086Metadata(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA: + res = dispatchSetBuffersCta8613Metadata(args); + break; case NATIVE_WINDOW_SET_SURFACE_DAMAGE: res = dispatchSetSurfaceDamage(args); break; @@ -1083,11 +1100,22 @@ int Surface::dispatchSetSidebandStream(va_list args) { } int Surface::dispatchSetBuffersDataSpace(va_list args) { - android_dataspace dataspace = - static_cast<android_dataspace>(va_arg(args, int)); + Dataspace dataspace = static_cast<Dataspace>(va_arg(args, int)); return setBuffersDataSpace(dataspace); } +int Surface::dispatchSetBuffersSmpte2086Metadata(va_list args) { + const android_smpte2086_metadata* metadata = + va_arg(args, const android_smpte2086_metadata*); + return setBuffersSmpte2086Metadata(metadata); +} + +int Surface::dispatchSetBuffersCta8613Metadata(va_list args) { + const android_cta861_3_metadata* metadata = + va_arg(args, const android_cta861_3_metadata*); + return setBuffersCta8613Metadata(metadata); +} + int Surface::dispatchSetSurfaceDamage(va_list args) { android_native_rect_t* rects = va_arg(args, android_native_rect_t*); size_t numRects = va_arg(args, size_t); @@ -1236,7 +1264,7 @@ int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer, ATRACE_CALL(); ALOGV("Surface::detachNextBuffer"); - if (outBuffer == nullptr || outFence == nullptr) { + if (outBuffer == NULL || outFence == NULL) { return BAD_VALUE; } @@ -1245,8 +1273,8 @@ int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer, mRemovedBuffers.clear(); } - sp<GraphicBuffer> buffer(nullptr); - sp<Fence> fence(nullptr); + sp<GraphicBuffer> buffer(NULL); + sp<Fence> fence(NULL); status_t result = mGraphicBufferProducer->detachNextBuffer( &buffer, &fence); if (result != NO_ERROR) { @@ -1254,19 +1282,19 @@ int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer, } *outBuffer = buffer; - if (fence != nullptr && fence->isValid()) { + if (fence != NULL && fence->isValid()) { *outFence = fence; } else { *outFence = Fence::NO_FENCE; } for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].buffer != nullptr && + if (mSlots[i].buffer != NULL && mSlots[i].buffer->getId() == buffer->getId()) { if (mReportRemovedBuffers) { mRemovedBuffers.push_back(mSlots[i].buffer); } - mSlots[i].buffer = nullptr; + mSlots[i].buffer = NULL; } } @@ -1317,7 +1345,7 @@ int Surface::setCrop(Rect const* rect) ATRACE_CALL(); Rect realRect(Rect::EMPTY_RECT); - if (rect == nullptr || rect->isEmpty()) { + if (rect == NULL || rect->isEmpty()) { realRect.clear(); } else { realRect = *rect; @@ -1504,7 +1532,7 @@ int Surface::setBuffersTimestamp(int64_t timestamp) return NO_ERROR; } -int Surface::setBuffersDataSpace(android_dataspace dataSpace) +int Surface::setBuffersDataSpace(Dataspace dataSpace) { ALOGV("Surface::setBuffersDataSpace"); Mutex::Autolock lock(mMutex); @@ -1512,9 +1540,39 @@ int Surface::setBuffersDataSpace(android_dataspace dataSpace) return NO_ERROR; } +int Surface::setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata) { + ALOGV("Surface::setBuffersSmpte2086Metadata"); + Mutex::Autolock lock(mMutex); + if (metadata) { + mHdrMetadata.smpte2086 = *metadata; + mHdrMetadata.validTypes |= HdrMetadata::SMPTE2086; + } else { + mHdrMetadata.validTypes &= ~HdrMetadata::SMPTE2086; + } + return NO_ERROR; +} + +int Surface::setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata) { + ALOGV("Surface::setBuffersCta8613Metadata"); + Mutex::Autolock lock(mMutex); + if (metadata) { + mHdrMetadata.cta8613 = *metadata; + mHdrMetadata.validTypes |= HdrMetadata::CTA861_3; + } else { + mHdrMetadata.validTypes &= ~HdrMetadata::CTA861_3; + } + return NO_ERROR; +} + +Dataspace Surface::getBuffersDataSpace() { + ALOGV("Surface::getBuffersDataSpace"); + Mutex::Autolock lock(mMutex); + return mDataSpace; +} + void Surface::freeAllBuffers() { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - mSlots[i].buffer = nullptr; + mSlots[i].buffer = 0; } } @@ -1554,12 +1612,12 @@ static status_t copyBlt( // src and dst with, height and format must be identical. no verification // is done here. status_t err; - uint8_t* src_bits = nullptr; + uint8_t* src_bits = NULL; err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), reinterpret_cast<void**>(&src_bits)); ALOGE_IF(err, "error locking src buffer %s", strerror(-err)); - uint8_t* dst_bits = nullptr; + uint8_t* dst_bits = NULL; err = dst->lockAsync(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), reinterpret_cast<void**>(&dst_bits), *dstFenceFd); ALOGE_IF(err, "error locking dst buffer %s", strerror(-err)); @@ -1607,7 +1665,7 @@ static status_t copyBlt( status_t Surface::lock( ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) { - if (mLockedBuffer != nullptr) { + if (mLockedBuffer != 0) { ALOGE("Surface::lock failed, already locked"); return INVALID_OPERATION; } @@ -1639,7 +1697,7 @@ status_t Surface::lock( // figure out if we can copy the frontbuffer back const sp<GraphicBuffer>& frontBuffer(mPostedBuffer); - const bool canCopyBack = (frontBuffer != nullptr && + const bool canCopyBack = (frontBuffer != 0 && backBuffer->width == frontBuffer->width && backBuffer->height == frontBuffer->height && backBuffer->format == frontBuffer->format); @@ -1701,7 +1759,7 @@ status_t Surface::lock( status_t Surface::unlockAndPost() { - if (mLockedBuffer == nullptr) { + if (mLockedBuffer == 0) { ALOGE("Surface::unlockAndPost failed, no locked buffer"); return INVALID_OPERATION; } @@ -1715,7 +1773,7 @@ status_t Surface::unlockAndPost() mLockedBuffer->handle, strerror(-err)); mPostedBuffer = mLockedBuffer; - mLockedBuffer = nullptr; + mLockedBuffer = 0; return err; } @@ -1754,4 +1812,25 @@ status_t Surface::getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out) return OK; } +status_t Surface::attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer) { + if (buffer == nullptr) { + return BAD_VALUE; + } + int err = static_cast<ANativeWindow*>(surface)->perform(surface, NATIVE_WINDOW_API_CONNECT, + NATIVE_WINDOW_API_CPU); + if (err != OK) { + return err; + } + err = surface->attachBuffer(buffer->getNativeBuffer()); + if (err != OK) { + return err; + } + err = static_cast<ANativeWindow*>(surface)->queueBuffer(surface, buffer->getNativeBuffer(), -1); + if (err != OK) { + return err; + } + err = surface->disconnect(NATIVE_WINDOW_API_CPU); + return err; +} + }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 053b9afb86..63560c4b89 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -21,7 +21,6 @@ #include <utils/Errors.h> #include <utils/Log.h> -#include <utils/Singleton.h> #include <utils/SortedVector.h> #include <utils/String8.h> #include <utils/threads.h> @@ -37,13 +36,15 @@ #include <gui/IGraphicBufferProducer.h> #include <gui/ISurfaceComposer.h> #include <gui/ISurfaceComposerClient.h> +#include <gui/LayerState.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> #include <private/gui/ComposerService.h> -#include <private/gui/LayerState.h> namespace android { + +using ui::ColorMode; // --------------------------------------------------------------------------- ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService); @@ -80,7 +81,7 @@ void ComposerService::connectLocked() { /*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() { ComposerService& instance = ComposerService::getInstance(); Mutex::Autolock _l(instance.mLock); - if (instance.mComposerService == nullptr) { + if (instance.mComposerService == NULL) { ComposerService::getInstance().connectLocked(); assert(instance.mComposerService != NULL); ALOGD("ComposerService reconnected"); @@ -91,239 +92,150 @@ void ComposerService::connectLocked() { void ComposerService::composerServiceDied() { Mutex::Autolock _l(mLock); - mComposerService = nullptr; - mDeathObserver = nullptr; + mComposerService = NULL; + mDeathObserver = NULL; } // --------------------------------------------------------------------------- -static inline -int compare_type(const ComposerState& lhs, const ComposerState& rhs) { - if (lhs.client < rhs.client) return -1; - if (lhs.client > rhs.client) return 1; - if (lhs.state.surface < rhs.state.surface) return -1; - if (lhs.state.surface > rhs.state.surface) return 1; - return 0; -} - -static inline -int compare_type(const DisplayState& lhs, const DisplayState& rhs) { - return compare_type(lhs.token, rhs.token); -} - -class Composer : public Singleton<Composer> -{ - friend class Singleton<Composer>; - - mutable Mutex mLock; - SortedVector<ComposerState> mComposerStates; - SortedVector<DisplayState > mDisplayStates; - uint32_t mForceSynchronous; - uint32_t mTransactionNestCount; - bool mAnimation; - - Composer() : Singleton<Composer>(), - mForceSynchronous(0), mTransactionNestCount(0), - mAnimation(false) - { } - - void openGlobalTransactionImpl(); - void closeGlobalTransactionImpl(bool synchronous); - void setAnimationTransactionImpl(); - status_t enableVSyncInjectionsImpl(bool enable); - status_t injectVSyncImpl(nsecs_t when); - - layer_state_t* getLayerStateLocked( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id); - - DisplayState& getDisplayStateLocked(const sp<IBinder>& token); - -public: - sp<IBinder> createDisplay(const String8& displayName, bool secure); - void destroyDisplay(const sp<IBinder>& display); - sp<IBinder> getBuiltInDisplay(int32_t id); - - status_t setPosition(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - float x, float y); - status_t setSize(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - uint32_t w, uint32_t h); - status_t setLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - int32_t z); - status_t setRelativeLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - const sp<IBinder>& relativeTo, int32_t z); - status_t setFlags(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - uint32_t flags, uint32_t mask); - status_t setTransparentRegionHint( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - const Region& transparentRegion); - status_t setAlpha(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - float alpha); - status_t setMatrix(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - float dsdx, float dtdx, float dtdy, float dsdy); - status_t setOrientation(int orientation); - status_t setCrop(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, - const Rect& crop); - status_t setFinalCrop(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const Rect& crop); - status_t setLayerStack(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, uint32_t layerStack); - status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const sp<IBinder>& handle, - uint64_t frameNumber); - status_t deferTransactionUntil(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const sp<Surface>& barrierSurface, - uint64_t frameNumber); - status_t reparentChildren(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, - const sp<IBinder>& newParentHandle); - status_t detachChildren(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id); - status_t setOverrideScalingMode(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, int32_t overrideScalingMode); - status_t setGeometryAppliesWithResize(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id); - - status_t setDisplaySurface(const sp<IBinder>& token, - sp<IGraphicBufferProducer> bufferProducer); - void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack); - void setDisplayProjection(const sp<IBinder>& token, - uint32_t orientation, - const Rect& layerStackRect, - const Rect& displayRect); - void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height); - - static void setAnimationTransaction() { - Composer::getInstance().setAnimationTransactionImpl(); - } - - static void openGlobalTransaction() { - Composer::getInstance().openGlobalTransactionImpl(); +SurfaceComposerClient::Transaction::Transaction(const Transaction& other) : + mForceSynchronous(other.mForceSynchronous), + mTransactionNestCount(other.mTransactionNestCount), + mAnimation(other.mAnimation), + mEarlyWakeup(other.mEarlyWakeup) { + mDisplayStates = other.mDisplayStates; + mComposerStates = other.mComposerStates; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) { + for (auto const& kv : other.mComposerStates) { + if (mComposerStates.count(kv.first) == 0) { + mComposerStates[kv.first] = kv.second; + } else { + mComposerStates[kv.first].state.merge(kv.second.state); + } } + other.mComposerStates.clear(); - static void closeGlobalTransaction(bool synchronous) { - Composer::getInstance().closeGlobalTransactionImpl(synchronous); + for (auto const& state : other.mDisplayStates) { + ssize_t index = mDisplayStates.indexOf(state); + if (index < 0) { + mDisplayStates.add(state); + } else { + mDisplayStates.editItemAt(static_cast<size_t>(index)).merge(state); + } } + other.mDisplayStates.clear(); - static status_t enableVSyncInjections(bool enable) { - return Composer::getInstance().enableVSyncInjectionsImpl(enable); - } + return *this; +} - static status_t injectVSync(nsecs_t when) { - return Composer::getInstance().injectVSyncImpl(when); +status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { + if (mStatus != NO_ERROR) { + return mStatus; } -}; - -ANDROID_SINGLETON_STATIC_INSTANCE(Composer); - -// --------------------------------------------------------------------------- -sp<IBinder> Composer::createDisplay(const String8& displayName, bool secure) { - return ComposerService::getComposerService()->createDisplay(displayName, - secure); -} + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); -void Composer::destroyDisplay(const sp<IBinder>& display) { - return ComposerService::getComposerService()->destroyDisplay(display); -} + Vector<ComposerState> composerStates; + Vector<DisplayState> displayStates; + uint32_t flags = 0; -sp<IBinder> Composer::getBuiltInDisplay(int32_t id) { - return ComposerService::getComposerService()->getBuiltInDisplay(id); -} + mForceSynchronous |= synchronous; -void Composer::openGlobalTransactionImpl() { - { // scope for the lock - Mutex::Autolock _l(mLock); - mTransactionNestCount += 1; + for (auto const& kv : mComposerStates){ + composerStates.add(kv.second); } -} -void Composer::closeGlobalTransactionImpl(bool synchronous) { - sp<ISurfaceComposer> sm(ComposerService::getComposerService()); - - Vector<ComposerState> transaction; - Vector<DisplayState> displayTransaction; - uint32_t flags = 0; + mComposerStates.clear(); - { // scope for the lock - Mutex::Autolock _l(mLock); - mForceSynchronous |= synchronous; - if (!mTransactionNestCount) { - ALOGW("At least one call to closeGlobalTransaction() was not matched by a prior " - "call to openGlobalTransaction()."); - } else if (--mTransactionNestCount) { - return; - } + displayStates = mDisplayStates; + mDisplayStates.clear(); - transaction = mComposerStates; - mComposerStates.clear(); + if (mForceSynchronous) { + flags |= ISurfaceComposer::eSynchronous; + } + if (mAnimation) { + flags |= ISurfaceComposer::eAnimation; + } + if (mEarlyWakeup) { + flags |= ISurfaceComposer::eEarlyWakeup; + } - displayTransaction = mDisplayStates; - mDisplayStates.clear(); + mForceSynchronous = false; + mAnimation = false; + mEarlyWakeup = false; - if (mForceSynchronous) { - flags |= ISurfaceComposer::eSynchronous; - } - if (mAnimation) { - flags |= ISurfaceComposer::eAnimation; - } + sf->setTransactionState(composerStates, displayStates, flags); + mStatus = NO_ERROR; + return NO_ERROR; +} - mForceSynchronous = false; - mAnimation = false; - } +// --------------------------------------------------------------------------- - sm->setTransactionState(transaction, displayTransaction, flags); +sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) { + return ComposerService::getComposerService()->createDisplay(displayName, + secure); } -status_t Composer::enableVSyncInjectionsImpl(bool enable) { - sp<ISurfaceComposer> sm(ComposerService::getComposerService()); - return sm->enableVSyncInjections(enable); +void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) { + return ComposerService::getComposerService()->destroyDisplay(display); } -status_t Composer::injectVSyncImpl(nsecs_t when) { - sp<ISurfaceComposer> sm(ComposerService::getComposerService()); - return sm->injectVSync(when); +sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) { + return ComposerService::getComposerService()->getBuiltInDisplay(id); } -void Composer::setAnimationTransactionImpl() { - Mutex::Autolock _l(mLock); +void SurfaceComposerClient::Transaction::setAnimationTransaction() { mAnimation = true; } -layer_state_t* Composer::getLayerStateLocked( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id) { - - ComposerState s; - s.client = client->mClient; - s.state.surface = id; +void SurfaceComposerClient::Transaction::setEarlyWakeup() { + mEarlyWakeup = true; +} - ssize_t index = mComposerStates.indexOf(s); - if (index < 0) { +layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) { + if (mComposerStates.count(sc) == 0) { // we don't have it, add an initialized layer_state to our list - index = mComposerStates.add(s); + ComposerState s; + s.client = sc->getClient()->mClient; + s.state.surface = sc->getHandle(); + mComposerStates[sc] = s; } - ComposerState* const out = mComposerStates.editArray(); - return &(out[index].state); + return &(mComposerStates[sc].state); } -status_t Composer::setPosition(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, float x, float y) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition( + const sp<SurfaceControl>& sc, float x, float y) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::ePositionChanged; s->x = x; s->y = y; - return NO_ERROR; + return *this; } -status_t Composer::setSize(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, uint32_t w, uint32_t h) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::show( + const sp<SurfaceControl>& sc) { + return setFlags(sc, 0, layer_state_t::eLayerHidden); +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::hide( + const sp<SurfaceControl>& sc) { + return setFlags(sc, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden); +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSize( + const sp<SurfaceControl>& sc, uint32_t w, uint32_t h) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eSizeChanged; s->w = w; s->h = h; @@ -331,41 +243,41 @@ status_t Composer::setSize(const sp<SurfaceComposerClient>& client, // Resizing a surface makes the transaction synchronous. mForceSynchronous = true; - return NO_ERROR; + return *this; } -status_t Composer::setLayer(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, int32_t z) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayer( + const sp<SurfaceControl>& sc, int32_t z) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eLayerChanged; s->z = z; - return NO_ERROR; + return *this; } -status_t Composer::setRelativeLayer(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const sp<IBinder>& relativeTo, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setRelativeLayer(const sp<SurfaceControl>& sc, const sp<IBinder>& relativeTo, int32_t z) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; } s->what |= layer_state_t::eRelativeLayerChanged; s->relativeLayerHandle = relativeTo; s->z = z; - return NO_ERROR; + return *this; } -status_t Composer::setFlags(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, uint32_t flags, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFlags( + const sp<SurfaceControl>& sc, uint32_t flags, uint32_t mask) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } if ((mask & layer_state_t::eLayerOpaque) || (mask & layer_state_t::eLayerHidden) || (mask & layer_state_t::eLayerSecure)) { @@ -374,50 +286,54 @@ status_t Composer::setFlags(const sp<SurfaceComposerClient>& client, s->flags &= ~mask; s->flags |= (flags & mask); s->mask |= mask; - return NO_ERROR; + return *this; } -status_t Composer::setTransparentRegionHint( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTransparentRegionHint( + const sp<SurfaceControl>& sc, const Region& transparentRegion) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eTransparentRegionChanged; s->transparentRegion = transparentRegion; - return NO_ERROR; + return *this; } -status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, float alpha) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha( + const sp<SurfaceControl>& sc, float alpha) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eAlphaChanged; s->alpha = alpha; - return NO_ERROR; + return *this; } -status_t Composer::setLayerStack(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, uint32_t layerStack) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayerStack( + const sp<SurfaceControl>& sc, uint32_t layerStack) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eLayerStackChanged; s->layerStack = layerStack; - return NO_ERROR; + return *this; } -status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, float dsdx, float dtdx, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMatrix( + const sp<SurfaceControl>& sc, float dsdx, float dtdx, float dtdy, float dsdy) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eMatrixChanged; layer_state_t::matrix22_t matrix; matrix.dsdx = dsdx; @@ -425,93 +341,115 @@ status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client, matrix.dsdy = dsdy; matrix.dtdy = dtdy; s->matrix = matrix; - return NO_ERROR; + return *this; } -status_t Composer::setCrop(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const Rect& crop) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); - if (!s) - return BAD_INDEX; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop( + const sp<SurfaceControl>& sc, const Rect& crop) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } s->what |= layer_state_t::eCropChanged; s->crop = crop; - return NO_ERROR; + return *this; } -status_t Composer::setFinalCrop(const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, const Rect& crop) { - Mutex::Autolock _l(mLock); - layer_state_t* s = getLayerStateLocked(client, id); +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop) { + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eFinalCropChanged; s->finalCrop = crop; - return NO_ERROR; + return *this; } -status_t Composer::deferTransactionUntil( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil( + const sp<SurfaceControl>& sc, const sp<IBinder>& handle, uint64_t frameNumber) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eDeferTransaction; s->barrierHandle = handle; s->frameNumber = frameNumber; - return NO_ERROR; + return *this; } -status_t Composer::deferTransactionUntil( - const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil( + const sp<SurfaceControl>& sc, const sp<Surface>& barrierSurface, uint64_t frameNumber) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eDeferTransaction; s->barrierGbp = barrierSurface->getIGraphicBufferProducer(); s->frameNumber = frameNumber; - return NO_ERROR; + return *this; } -status_t Composer::reparentChildren( - const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparentChildren( + const sp<SurfaceControl>& sc, const sp<IBinder>& newParentHandle) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eReparentChildren; s->reparentHandle = newParentHandle; - return NO_ERROR; + return *this; } -status_t Composer::detachChildren( - const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent( + const sp<SurfaceControl>& sc, + const sp<IBinder>& newParentHandle) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eReparent; + s->parentHandleForChild = newParentHandle; + return *this; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColor( + const sp<SurfaceControl>& sc, + const half3& color) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eColorChanged; + s->color = color; + return *this; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachChildren( + const sp<SurfaceControl>& sc) { + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; } s->what |= layer_state_t::eDetachChildren; - return NO_ERROR; + return *this; } -status_t Composer::setOverrideScalingMode( - const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id, int32_t overrideScalingMode) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setOverrideScalingMode( + const sp<SurfaceControl>& sc, int32_t overrideScalingMode) { + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } switch (overrideScalingMode) { @@ -524,29 +462,40 @@ status_t Composer::setOverrideScalingMode( default: ALOGE("unknown scaling mode: %d", overrideScalingMode); - return BAD_VALUE; + mStatus = BAD_VALUE; + return *this; } s->what |= layer_state_t::eOverrideScalingModeChanged; s->overrideScalingMode = overrideScalingMode; - return NO_ERROR; + return *this; } -status_t Composer::setGeometryAppliesWithResize( - const sp<SurfaceComposerClient>& client, - const sp<IBinder>& id) { - Mutex::Autolock lock(mLock); - layer_state_t* s = getLayerStateLocked(client, id); +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeometryAppliesWithResize( + const sp<SurfaceControl>& sc) { + layer_state_t* s = getLayerState(sc); if (!s) { - return BAD_INDEX; + mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eGeometryAppliesWithResize; - return NO_ERROR; + return *this; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::destroySurface( + const sp<SurfaceControl>& sc) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eDestroySurface; + return *this; } // --------------------------------------------------------------------------- -DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) { +DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) { DisplayState s; s.token = token; ssize_t index = mDisplayStates.indexOf(s); @@ -558,8 +507,8 @@ DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) { return mDisplayStates.editItemAt(static_cast<size_t>(index)); } -status_t Composer::setDisplaySurface(const sp<IBinder>& token, - sp<IGraphicBufferProducer> bufferProducer) { +status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp<IBinder>& token, + const sp<IGraphicBufferProducer>& bufferProducer) { if (bufferProducer.get() != nullptr) { // Make sure that composition can never be stalled by a virtual display // consumer that isn't processing buffers fast enough. @@ -571,27 +520,24 @@ status_t Composer::setDisplaySurface(const sp<IBinder>& token, return err; } } - Mutex::Autolock _l(mLock); - DisplayState& s(getDisplayStateLocked(token)); + DisplayState& s(getDisplayState(token)); s.surface = bufferProducer; s.what |= DisplayState::eSurfaceChanged; return NO_ERROR; } -void Composer::setDisplayLayerStack(const sp<IBinder>& token, +void SurfaceComposerClient::Transaction::setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack) { - Mutex::Autolock _l(mLock); - DisplayState& s(getDisplayStateLocked(token)); + DisplayState& s(getDisplayState(token)); s.layerStack = layerStack; s.what |= DisplayState::eLayerStackChanged; } -void Composer::setDisplayProjection(const sp<IBinder>& token, +void SurfaceComposerClient::Transaction::setDisplayProjection(const sp<IBinder>& token, uint32_t orientation, const Rect& layerStackRect, const Rect& displayRect) { - Mutex::Autolock _l(mLock); - DisplayState& s(getDisplayStateLocked(token)); + DisplayState& s(getDisplayState(token)); s.orientation = orientation; s.viewport = layerStackRect; s.frame = displayRect; @@ -599,9 +545,8 @@ void Composer::setDisplayProjection(const sp<IBinder>& token, mForceSynchronous = true; // TODO: do we actually still need this? } -void Composer::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height) { - Mutex::Autolock _l(mLock); - DisplayState& s(getDisplayStateLocked(token)); +void SurfaceComposerClient::Transaction::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height) { + DisplayState& s(getDisplayState(token)); s.width = width; s.height = height; s.what |= DisplayState::eDisplaySizeChanged; @@ -610,23 +555,28 @@ void Composer::setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t // --------------------------------------------------------------------------- SurfaceComposerClient::SurfaceComposerClient() - : mStatus(NO_INIT), mComposer(Composer::getInstance()) + : mStatus(NO_INIT) { } SurfaceComposerClient::SurfaceComposerClient(const sp<IGraphicBufferProducer>& root) - : mStatus(NO_INIT), mComposer(Composer::getInstance()), mParent(root) + : mStatus(NO_INIT), mParent(root) +{ +} + +SurfaceComposerClient::SurfaceComposerClient(const sp<ISurfaceComposerClient>& client) + : mStatus(NO_ERROR), mClient(client) { } void SurfaceComposerClient::onFirstRef() { - sp<ISurfaceComposer> sm(ComposerService::getComposerService()); - if (sm != nullptr) { + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + if (sf != 0 && mStatus == NO_INIT) { auto rootProducer = mParent.promote(); sp<ISurfaceComposerClient> conn; - conn = (rootProducer != nullptr) ? sm->createScopedConnection(rootProducer) : - sm->createConnection(); - if (conn != nullptr) { + conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) : + sf->createConnection(); + if (conn != 0) { mClient = conn; mStatus = NO_ERROR; } @@ -648,15 +598,15 @@ sp<IBinder> SurfaceComposerClient::connection() const { status_t SurfaceComposerClient::linkToComposerDeath( const sp<IBinder::DeathRecipient>& recipient, void* cookie, uint32_t flags) { - sp<ISurfaceComposer> sm(ComposerService::getComposerService()); - return IInterface::asBinder(sm)->linkToDeath(recipient, cookie, flags); + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + return IInterface::asBinder(sf)->linkToDeath(recipient, cookie, flags); } void SurfaceComposerClient::dispose() { // this can be called more than once. sp<ISurfaceComposerClient> client; Mutex::Autolock _lm(mLock); - if (mClient != nullptr) { + if (mClient != 0) { client = mClient; // hold ref while lock is held mClient.clear(); } @@ -670,10 +620,28 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( PixelFormat format, uint32_t flags, SurfaceControl* parent, - uint32_t windowType, - uint32_t ownerUid) + int32_t windowType, + int32_t ownerUid) +{ + sp<SurfaceControl> s; + createSurfaceChecked(name, w, h, format, &s, flags, parent, windowType, ownerUid); + return s; +} + +status_t SurfaceComposerClient::createSurfaceChecked( + const String8& name, + uint32_t w, + uint32_t h, + PixelFormat format, + sp<SurfaceControl>* outSurface, + uint32_t flags, + SurfaceControl* parent, + int32_t windowType, + int32_t ownerUid) { sp<SurfaceControl> sur; + status_t err = mStatus; + if (mStatus == NO_ERROR) { sp<IBinder> handle; sp<IBinder> parentHandle; @@ -682,27 +650,14 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( if (parent != nullptr) { parentHandle = parent->getHandle(); } - status_t err = mClient->createSurface(name, w, h, format, flags, parentHandle, + err = mClient->createSurface(name, w, h, format, flags, parentHandle, windowType, ownerUid, &handle, &gbp); ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err)); if (err == NO_ERROR) { - sur = new SurfaceControl(this, handle, gbp); + *outSurface = new SurfaceControl(this, handle, gbp, true /* owned */); } } - return sur; -} - -sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, - bool secure) { - return Composer::getInstance().createDisplay(displayName, secure); -} - -void SurfaceComposerClient::destroyDisplay(const sp<IBinder>& display) { - Composer::getInstance().destroyDisplay(display); -} - -sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) { - return Composer::getInstance().getBuiltInDisplay(id); + return err; } status_t SurfaceComposerClient::destroySurface(const sp<IBinder>& sid) { @@ -727,152 +682,18 @@ status_t SurfaceComposerClient::getLayerFrameStats(const sp<IBinder>& token, return mClient->getLayerFrameStats(token, outStats); } -inline Composer& SurfaceComposerClient::getComposer() { - return mComposer; -} - // ---------------------------------------------------------------------------- -void SurfaceComposerClient::openGlobalTransaction() { - Composer::openGlobalTransaction(); -} - -void SurfaceComposerClient::closeGlobalTransaction(bool synchronous) { - Composer::closeGlobalTransaction(synchronous); -} - -void SurfaceComposerClient::setAnimationTransaction() { - Composer::setAnimationTransaction(); -} - status_t SurfaceComposerClient::enableVSyncInjections(bool enable) { - return Composer::enableVSyncInjections(enable); + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + return sf->enableVSyncInjections(enable); } status_t SurfaceComposerClient::injectVSync(nsecs_t when) { - return Composer::injectVSync(when); -} - -// ---------------------------------------------------------------------------- - -status_t SurfaceComposerClient::setCrop(const sp<IBinder>& id, const Rect& crop) { - return getComposer().setCrop(this, id, crop); -} - -status_t SurfaceComposerClient::setFinalCrop(const sp<IBinder>& id, - const Rect& crop) { - return getComposer().setFinalCrop(this, id, crop); -} - -status_t SurfaceComposerClient::setPosition(const sp<IBinder>& id, float x, float y) { - return getComposer().setPosition(this, id, x, y); -} - -status_t SurfaceComposerClient::setSize(const sp<IBinder>& id, uint32_t w, uint32_t h) { - return getComposer().setSize(this, id, w, h); -} - -status_t SurfaceComposerClient::setLayer(const sp<IBinder>& id, int32_t z) { - return getComposer().setLayer(this, id, z); -} - -status_t SurfaceComposerClient::setRelativeLayer(const sp<IBinder>& id, - const sp<IBinder>& relativeTo, int32_t z) { - return getComposer().setRelativeLayer(this, id, relativeTo, z); -} - -status_t SurfaceComposerClient::hide(const sp<IBinder>& id) { - return getComposer().setFlags(this, id, - layer_state_t::eLayerHidden, - layer_state_t::eLayerHidden); -} - -status_t SurfaceComposerClient::show(const sp<IBinder>& id) { - return getComposer().setFlags(this, id, - 0, - layer_state_t::eLayerHidden); -} - -status_t SurfaceComposerClient::setFlags(const sp<IBinder>& id, uint32_t flags, - uint32_t mask) { - return getComposer().setFlags(this, id, flags, mask); -} - -status_t SurfaceComposerClient::setTransparentRegionHint(const sp<IBinder>& id, - const Region& transparentRegion) { - return getComposer().setTransparentRegionHint(this, id, transparentRegion); -} - -status_t SurfaceComposerClient::setAlpha(const sp<IBinder>& id, float alpha) { - return getComposer().setAlpha(this, id, alpha); -} - -status_t SurfaceComposerClient::setLayerStack(const sp<IBinder>& id, uint32_t layerStack) { - return getComposer().setLayerStack(this, id, layerStack); -} - -status_t SurfaceComposerClient::setMatrix(const sp<IBinder>& id, float dsdx, float dtdx, - float dtdy, float dsdy) { - return getComposer().setMatrix(this, id, dsdx, dtdx, dtdy, dsdy); -} - -status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id, - const sp<IBinder>& handle, uint64_t frameNumber) { - return getComposer().deferTransactionUntil(this, id, handle, frameNumber); -} - -status_t SurfaceComposerClient::deferTransactionUntil(const sp<IBinder>& id, - const sp<Surface>& barrierSurface, uint64_t frameNumber) { - return getComposer().deferTransactionUntil(this, id, barrierSurface, frameNumber); -} - -status_t SurfaceComposerClient::reparentChildren(const sp<IBinder>& id, - const sp<IBinder>& newParentHandle) { - return getComposer().reparentChildren(this, id, newParentHandle); -} - -status_t SurfaceComposerClient::detachChildren(const sp<IBinder>& id) { - return getComposer().detachChildren(this, id); -} - -status_t SurfaceComposerClient::setOverrideScalingMode( - const sp<IBinder>& id, int32_t overrideScalingMode) { - return getComposer().setOverrideScalingMode( - this, id, overrideScalingMode); + sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + return sf->injectVSync(when); } -status_t SurfaceComposerClient::setGeometryAppliesWithResize( - const sp<IBinder>& id) { - return getComposer().setGeometryAppliesWithResize(this, id); -} - -// ---------------------------------------------------------------------------- - -status_t SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token, - sp<IGraphicBufferProducer> bufferProducer) { - return Composer::getInstance().setDisplaySurface(token, bufferProducer); -} - -void SurfaceComposerClient::setDisplayLayerStack(const sp<IBinder>& token, - uint32_t layerStack) { - Composer::getInstance().setDisplayLayerStack(token, layerStack); -} - -void SurfaceComposerClient::setDisplayProjection(const sp<IBinder>& token, - uint32_t orientation, - const Rect& layerStackRect, - const Rect& displayRect) { - Composer::getInstance().setDisplayProjection(token, orientation, - layerStackRect, displayRect); -} - -void SurfaceComposerClient::setDisplaySize(const sp<IBinder>& token, - uint32_t width, uint32_t height) { - Composer::getInstance().setDisplaySize(token, width, height); -} - -// ---------------------------------------------------------------------------- - status_t SurfaceComposerClient::getDisplayConfigs( const sp<IBinder>& display, Vector<DisplayInfo>* configs) { @@ -906,16 +727,16 @@ status_t SurfaceComposerClient::setActiveConfig(const sp<IBinder>& display, int } status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display, - Vector<android_color_mode_t>* outColorModes) { + Vector<ColorMode>* outColorModes) { return ComposerService::getComposerService()->getDisplayColorModes(display, outColorModes); } -android_color_mode_t SurfaceComposerClient::getActiveColorMode(const sp<IBinder>& display) { +ColorMode SurfaceComposerClient::getActiveColorMode(const sp<IBinder>& display) { return ComposerService::getComposerService()->getActiveColorMode(display); } status_t SurfaceComposerClient::setActiveColorMode(const sp<IBinder>& display, - android_color_mode_t colorMode) { + ColorMode colorMode) { return ComposerService::getComposerService()->setActiveColorMode(display, colorMode); } @@ -940,149 +761,37 @@ status_t SurfaceComposerClient::getHdrCapabilities(const sp<IBinder>& display, // ---------------------------------------------------------------------------- -status_t ScreenshotClient::capture( - const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform) { - sp<ISurfaceComposer> s(ComposerService::getComposerService()); - if (s == nullptr) return NO_INIT; - return s->captureScreen(display, producer, sourceCrop, - reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform); -} - -status_t ScreenshotClient::captureToBuffer(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, - uint32_t rotation, - sp<GraphicBuffer>* outBuffer) { +status_t ScreenshotClient::capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth, + uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ, + bool useIdentityTransform, uint32_t rotation, + sp<GraphicBuffer>* outBuffer) { sp<ISurfaceComposer> s(ComposerService::getComposerService()); - if (s == nullptr) return NO_INIT; - - sp<IGraphicBufferConsumer> gbpConsumer; - sp<IGraphicBufferProducer> producer; - BufferQueue::createBufferQueue(&producer, &gbpConsumer); - sp<BufferItemConsumer> consumer(new BufferItemConsumer(gbpConsumer, - GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_NEVER, - 1, true)); - - status_t ret = s->captureScreen(display, producer, sourceCrop, reqWidth, reqHeight, - minLayerZ, maxLayerZ, useIdentityTransform, - static_cast<ISurfaceComposer::Rotation>(rotation)); + if (s == NULL) return NO_INIT; + status_t ret = s->captureScreen(display, outBuffer, sourceCrop, reqWidth, reqHeight, minLayerZ, + maxLayerZ, useIdentityTransform, + static_cast<ISurfaceComposer::Rotation>(rotation)); if (ret != NO_ERROR) { return ret; } - BufferItem b; - consumer->acquireBuffer(&b, 0, true); - *outBuffer = b.mGraphicBuffer; return ret; } -ScreenshotClient::ScreenshotClient() - : mHaveBuffer(false) { - memset(&mBuffer, 0, sizeof(mBuffer)); -} - -ScreenshotClient::~ScreenshotClient() { - ScreenshotClient::release(); -} - -sp<CpuConsumer> ScreenshotClient::getCpuConsumer() const { - if (mCpuConsumer == nullptr) { - sp<IGraphicBufferConsumer> consumer; - BufferQueue::createBufferQueue(&mProducer, &consumer); - mCpuConsumer = new CpuConsumer(consumer, 1); - mCpuConsumer->setName(String8("ScreenshotClient")); - } - return mCpuConsumer; -} - -status_t ScreenshotClient::update(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, uint32_t rotation) { +status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, + float frameScale, sp<GraphicBuffer>* outBuffer) { sp<ISurfaceComposer> s(ComposerService::getComposerService()); - if (s == nullptr) return NO_INIT; - sp<CpuConsumer> cpuConsumer = getCpuConsumer(); - - if (mHaveBuffer) { - mCpuConsumer->unlockBuffer(mBuffer); - memset(&mBuffer, 0, sizeof(mBuffer)); - mHaveBuffer = false; - } - - status_t err = s->captureScreen(display, mProducer, sourceCrop, - reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform, - static_cast<ISurfaceComposer::Rotation>(rotation)); - - if (err == NO_ERROR) { - err = mCpuConsumer->lockNextBuffer(&mBuffer); - if (err == NO_ERROR) { - mHaveBuffer = true; - } - } - return err; -} - -status_t ScreenshotClient::update(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform) { - - return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight, - minLayerZ, maxLayerZ, useIdentityTransform, ISurfaceComposer::eRotateNone); -} - -status_t ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop, - bool useIdentityTransform) { - return ScreenshotClient::update(display, sourceCrop, 0, 0, - INT32_MIN, INT32_MAX, - useIdentityTransform, ISurfaceComposer::eRotateNone); -} - -status_t ScreenshotClient::update(const sp<IBinder>& display, Rect sourceCrop, - uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform) { - return ScreenshotClient::update(display, sourceCrop, reqWidth, reqHeight, - INT32_MIN, INT32_MAX, - useIdentityTransform, ISurfaceComposer::eRotateNone); -} - -void ScreenshotClient::release() { - if (mHaveBuffer) { - mCpuConsumer->unlockBuffer(mBuffer); - memset(&mBuffer, 0, sizeof(mBuffer)); - mHaveBuffer = false; - } - mCpuConsumer.clear(); -} - -void const* ScreenshotClient::getPixels() const { - return mBuffer.data; -} - -uint32_t ScreenshotClient::getWidth() const { - return mBuffer.width; -} - -uint32_t ScreenshotClient::getHeight() const { - return mBuffer.height; -} - -PixelFormat ScreenshotClient::getFormat() const { - return mBuffer.format; -} - -uint32_t ScreenshotClient::getStride() const { - return mBuffer.stride; -} - -size_t ScreenshotClient::getSize() const { - return mBuffer.stride * mBuffer.height * bytesPerPixel(mBuffer.format); + if (s == NULL) return NO_INIT; + status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale, + false /* childrenOnly */); + return ret; } -android_dataspace ScreenshotClient::getDataSpace() const { - return mBuffer.dataSpace; +status_t ScreenshotClient::captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, + float frameScale, sp<GraphicBuffer>* outBuffer) { + sp<ISurfaceComposer> s(ComposerService::getComposerService()); + if (s == NULL) return NO_INIT; + status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale, + true /* childrenOnly */); + return ret; } - // ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 08e3b60f6c..5eafbb3555 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -48,8 +48,9 @@ namespace android { SurfaceControl::SurfaceControl( const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle, - const sp<IGraphicBufferProducer>& gbp) - : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp) + const sp<IGraphicBufferProducer>& gbp, + bool owned) + : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp), mOwned(owned) { } @@ -60,7 +61,9 @@ SurfaceControl::~SurfaceControl() void SurfaceControl::destroy() { - if (isValid()) { + // Avoid destroying the server-side surface if we are not the owner of it, meaning that we + // retrieved it from another process. + if (isValid() && mOwned) { mClient->destroySurface(mHandle); } // clear all references and trigger an IPC now, to make sure things @@ -83,7 +86,7 @@ void SurfaceControl::clear() } void SurfaceControl::disconnect() { - if (mGraphicBufferProducer != nullptr) { + if (mGraphicBufferProducer != NULL) { mGraphicBufferProducer->disconnect( BufferQueueCore::CURRENTLY_CONNECTED_API); } @@ -92,117 +95,11 @@ void SurfaceControl::disconnect() { bool SurfaceControl::isSameSurface( const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs) { - if (lhs == nullptr || rhs == nullptr) + if (lhs == 0 || rhs == 0) return false; return lhs->mHandle == rhs->mHandle; } -status_t SurfaceControl::setLayerStack(uint32_t layerStack) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setLayerStack(mHandle, layerStack); -} - -status_t SurfaceControl::setLayer(int32_t layer) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setLayer(mHandle, layer); -} - -status_t SurfaceControl::setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setRelativeLayer(mHandle, relativeTo, layer); -} - -status_t SurfaceControl::setPosition(float x, float y) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setPosition(mHandle, x, y); -} -status_t SurfaceControl::setGeometryAppliesWithResize() { - status_t err = validate(); - if (err < 0) return err; - return mClient->setGeometryAppliesWithResize(mHandle); -} -status_t SurfaceControl::setSize(uint32_t w, uint32_t h) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setSize(mHandle, w, h); -} -status_t SurfaceControl::hide() { - status_t err = validate(); - if (err < 0) return err; - return mClient->hide(mHandle); -} -status_t SurfaceControl::show() { - status_t err = validate(); - if (err < 0) return err; - return mClient->show(mHandle); -} -status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setFlags(mHandle, flags, mask); -} -status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setTransparentRegionHint(mHandle, transparent); -} -status_t SurfaceControl::setAlpha(float alpha) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setAlpha(mHandle, alpha); -} -status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dtdy, float dsdy) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setMatrix(mHandle, dsdx, dtdx, dtdy, dsdy); -} -status_t SurfaceControl::setCrop(const Rect& crop) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setCrop(mHandle, crop); -} -status_t SurfaceControl::setFinalCrop(const Rect& crop) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setFinalCrop(mHandle, crop); -} - -status_t SurfaceControl::deferTransactionUntil(const sp<IBinder>& handle, - uint64_t frameNumber) { - status_t err = validate(); - if (err < 0) return err; - return mClient->deferTransactionUntil(mHandle, handle, frameNumber); -} - -status_t SurfaceControl::deferTransactionUntil(const sp<Surface>& handle, - uint64_t frameNumber) { - status_t err = validate(); - if (err < 0) return err; - return mClient->deferTransactionUntil(mHandle, handle, frameNumber); -} - -status_t SurfaceControl::reparentChildren(const sp<IBinder>& newParentHandle) { - status_t err = validate(); - if (err < 0) return err; - return mClient->reparentChildren(mHandle, newParentHandle); -} - -status_t SurfaceControl::detachChildren() { - status_t err = validate(); - if (err < 0) return err; - return mClient->detachChildren(mHandle); -} - -status_t SurfaceControl::setOverrideScalingMode(int32_t overrideScalingMode) { - status_t err = validate(); - if (err < 0) return err; - return mClient->setOverrideScalingMode(mHandle, overrideScalingMode); -} - status_t SurfaceControl::clearLayerFrameStats() const { status_t err = validate(); if (err < 0) return err; @@ -219,7 +116,7 @@ status_t SurfaceControl::getLayerFrameStats(FrameStats* outStats) const { status_t SurfaceControl::validate() const { - if (mHandle==nullptr || mClient==nullptr) { + if (mHandle==0 || mClient==0) { ALOGE("invalid handle (%p) or client (%p)", mHandle.get(), mClient.get()); return NO_INIT; @@ -231,7 +128,7 @@ status_t SurfaceControl::writeSurfaceToParcel( const sp<SurfaceControl>& control, Parcel* parcel) { sp<IGraphicBufferProducer> bp; - if (control != nullptr) { + if (control != NULL) { bp = control->mGraphicBufferProducer; } return parcel->writeStrongBinder(IInterface::asBinder(bp)); @@ -249,7 +146,7 @@ sp<Surface> SurfaceControl::generateSurfaceLocked() const sp<Surface> SurfaceControl::getSurface() const { Mutex::Autolock _l(mLock); - if (mSurfaceData == nullptr) { + if (mSurfaceData == 0) { return generateSurfaceLocked(); } return mSurfaceData; @@ -267,5 +164,35 @@ sp<IBinder> SurfaceControl::getHandle() const return mHandle; } +sp<SurfaceComposerClient> SurfaceControl::getClient() const +{ + return mClient; +} + +void SurfaceControl::writeToParcel(Parcel* parcel) +{ + parcel->writeStrongBinder(ISurfaceComposerClient::asBinder(mClient->getClient())); + parcel->writeStrongBinder(mHandle); + parcel->writeStrongBinder(IGraphicBufferProducer::asBinder(mGraphicBufferProducer)); +} + +sp<SurfaceControl> SurfaceControl::readFromParcel(Parcel* parcel) +{ + sp<IBinder> client = parcel->readStrongBinder(); + sp<IBinder> handle = parcel->readStrongBinder(); + if (client == nullptr || handle == nullptr) + { + ALOGE("Invalid parcel"); + return nullptr; + } + sp<IBinder> gbp; + parcel->readNullableStrongBinder(&gbp); + + // We aren't the original owner of the surface. + return new SurfaceControl(new SurfaceComposerClient( + interface_cast<ISurfaceComposerClient>(client)), + handle.get(), interface_cast<IGraphicBufferProducer>(gbp), false /* owned */); +} + // ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/gui/SyncFeatures.cpp b/libs/gui/SyncFeatures.cpp index fcae05c8ad..afa15c5cda 100644 --- a/libs/gui/SyncFeatures.cpp +++ b/libs/gui/SyncFeatures.cpp @@ -41,7 +41,7 @@ SyncFeatures::SyncFeatures() : Singleton<SyncFeatures>(), // This can only be called after EGL has been initialized; otherwise the // check below will abort. const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS); - LOG_ALWAYS_FATAL_IF(exts == nullptr, "eglQueryStringImplementationANDROID failed"); + LOG_ALWAYS_FATAL_IF(exts == NULL, "eglQueryStringImplementationANDROID failed"); if (strstr(exts, "EGL_ANDROID_native_fence_sync")) { // This makes GLConsumer use the EGL_ANDROID_native_fence_sync // extension to create Android native fences to signal when all diff --git a/libs/gui/include/gui/BufferHubConsumer.h b/libs/gui/include/gui/BufferHubConsumer.h new file mode 100644 index 0000000000..d38077014b --- /dev/null +++ b/libs/gui/include/gui/BufferHubConsumer.h @@ -0,0 +1,112 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_BUFFERHUBCONSUMER_H_ +#define ANDROID_GUI_BUFFERHUBCONSUMER_H_ + +#include <gui/IGraphicBufferConsumer.h> +#include <private/dvr/buffer_hub_queue_client.h> +#include <private/dvr/buffer_hub_queue_parcelable.h> + +namespace android { + +class BufferHubConsumer : public IGraphicBufferConsumer { +public: + // Creates a BufferHubConsumer instance by importing an existing producer queue. + static sp<BufferHubConsumer> Create(const std::shared_ptr<dvr::ConsumerQueue>& queue); + + // Creates a BufferHubConsumer instance by importing an existing producer + // parcelable. Note that this call takes the ownership of the parcelable + // object and is guaranteed to succeed if parcelable object is valid. + static sp<BufferHubConsumer> Create(dvr::ConsumerQueueParcelable parcelable); + + // See |IGraphicBufferConsumer::acquireBuffer| + status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen, + uint64_t maxFrameNumber = 0) override; + + // See |IGraphicBufferConsumer::detachBuffer| + status_t detachBuffer(int slot) override; + + // See |IGraphicBufferConsumer::attachBuffer| + status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer) override; + + // See |IGraphicBufferConsumer::releaseBuffer| + status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display, EGLSyncKHR fence, + const sp<Fence>& releaseFence) override; + + // See |IGraphicBufferConsumer::consumerConnect| + status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) override; + + // See |IGraphicBufferConsumer::consumerDisconnect| + status_t consumerDisconnect() override; + + // See |IGraphicBufferConsumer::getReleasedBuffers| + status_t getReleasedBuffers(uint64_t* slotMask) override; + + // See |IGraphicBufferConsumer::setDefaultBufferSize| + status_t setDefaultBufferSize(uint32_t w, uint32_t h) override; + + // See |IGraphicBufferConsumer::setMaxBufferCount| + status_t setMaxBufferCount(int bufferCount) override; + + // See |IGraphicBufferConsumer::setMaxAcquiredBufferCount| + status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) override; + + // See |IGraphicBufferConsumer::setConsumerName| + status_t setConsumerName(const String8& name) override; + + // See |IGraphicBufferConsumer::setDefaultBufferFormat| + status_t setDefaultBufferFormat(PixelFormat defaultFormat) override; + + // See |IGraphicBufferConsumer::setDefaultBufferDataSpace| + status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace) override; + + // See |IGraphicBufferConsumer::setConsumerUsageBits| + status_t setConsumerUsageBits(uint64_t usage) override; + + // See |IGraphicBufferConsumer::setConsumerIsProtected| + status_t setConsumerIsProtected(bool isProtected) override; + + // See |IGraphicBufferConsumer::setTransformHint| + status_t setTransformHint(uint32_t hint) override; + + // See |IGraphicBufferConsumer::getSidebandStream| + status_t getSidebandStream(sp<NativeHandle>* outStream) const override; + + // See |IGraphicBufferConsumer::getOccupancyHistory| + status_t getOccupancyHistory(bool forceFlush, + std::vector<OccupancyTracker::Segment>* outHistory) override; + + // See |IGraphicBufferConsumer::discardFreeBuffers| + status_t discardFreeBuffers() override; + + // See |IGraphicBufferConsumer::dumpState| + status_t dumpState(const String8& prefix, String8* outResult) const override; + + // BufferHubConsumer provides its own logic to cast to a binder object. + IBinder* onAsBinder() override; + +private: + // Private constructor to force use of |Create|. + BufferHubConsumer() = default; + + // Concrete implementation backed by BufferHubBuffer. + std::shared_ptr<dvr::ConsumerQueue> mQueue; +}; + +} // namespace android + +#endif // ANDROID_GUI_BUFFERHUBCONSUMER_H_ diff --git a/libs/gui/include/gui/BufferHubProducer.h b/libs/gui/include/gui/BufferHubProducer.h new file mode 100644 index 0000000000..23c9909826 --- /dev/null +++ b/libs/gui/include/gui/BufferHubProducer.h @@ -0,0 +1,219 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_GUI_BUFFERHUBPRODUCER_H_ +#define ANDROID_GUI_BUFFERHUBPRODUCER_H_ + +#include <gui/BufferSlot.h> +#include <gui/IGraphicBufferProducer.h> +#include <private/dvr/buffer_hub_queue_client.h> +#include <private/dvr/buffer_hub_queue_parcelable.h> + +namespace android { + +class BufferHubProducer : public IGraphicBufferProducer { +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; + + // Creates a BufferHubProducer instance by importing an existing prodcuer + // queue. + static sp<BufferHubProducer> Create(const std::shared_ptr<dvr::ProducerQueue>& producer); + + // Creates a BufferHubProducer instance by importing an existing prodcuer + // parcelable. Note that this call takes the ownership of the parcelable + // object and is guaranteed to succeed if parcelable object is valid. + static sp<BufferHubProducer> Create(dvr::ProducerQueueParcelable parcelable); + + // See |IGraphicBufferProducer::requestBuffer| + status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override; + + // For the BufferHub based implementation. All buffers in the queue are + // allowed to be dequeued from the consumer side. It call always returns + // 0 for |NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS| query. Thus setting + // |max_dequeued_buffers| here can be considered the same as setting queue + // capacity. + // + // See |IGraphicBufferProducer::setMaxDequeuedBufferCount| for more info + status_t setMaxDequeuedBufferCount(int max_dequeued_buffers) override; + + // See |IGraphicBufferProducer::setAsyncMode| + status_t setAsyncMode(bool async) override; + + // See |IGraphicBufferProducer::dequeueBuffer| + status_t dequeueBuffer(int* out_slot, sp<Fence>* out_fence, uint32_t width, uint32_t height, + PixelFormat format, uint64_t usage, uint64_t* outBufferAge, + FrameEventHistoryDelta* outTimestamps) override; + + // See |IGraphicBufferProducer::detachBuffer| + status_t detachBuffer(int slot) override; + + // See |IGraphicBufferProducer::detachNextBuffer| + status_t detachNextBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence) override; + + // See |IGraphicBufferProducer::attachBuffer| + status_t attachBuffer(int* out_slot, const sp<GraphicBuffer>& buffer) override; + + // See |IGraphicBufferProducer::queueBuffer| + status_t queueBuffer(int slot, const QueueBufferInput& input, + QueueBufferOutput* output) override; + + // See |IGraphicBufferProducer::cancelBuffer| + status_t cancelBuffer(int slot, const sp<Fence>& fence) override; + + // See |IGraphicBufferProducer::query| + status_t query(int what, int* out_value) override; + + // See |IGraphicBufferProducer::connect| + status_t connect(const sp<IProducerListener>& listener, int api, + bool producer_controlled_by_app, QueueBufferOutput* output) override; + + // See |IGraphicBufferProducer::disconnect| + status_t disconnect(int api, DisconnectMode mode = DisconnectMode::Api) override; + + // See |IGraphicBufferProducer::setSidebandStream| + status_t setSidebandStream(const sp<NativeHandle>& stream) override; + + // See |IGraphicBufferProducer::allocateBuffers| + void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, + uint64_t usage) override; + + // See |IGraphicBufferProducer::allowAllocation| + status_t allowAllocation(bool allow) override; + + // See |IGraphicBufferProducer::setGenerationNumber| + status_t setGenerationNumber(uint32_t generation_number) override; + + // See |IGraphicBufferProducer::getConsumerName| + String8 getConsumerName() const override; + + // See |IGraphicBufferProducer::setSharedBufferMode| + status_t setSharedBufferMode(bool shared_buffer_mode) override; + + // See |IGraphicBufferProducer::setAutoRefresh| + status_t setAutoRefresh(bool auto_refresh) override; + + // See |IGraphicBufferProducer::setDequeueTimeout| + status_t setDequeueTimeout(nsecs_t timeout) override; + + // See |IGraphicBufferProducer::getLastQueuedBuffer| + status_t getLastQueuedBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence, + float out_transform_matrix[16]) override; + + // See |IGraphicBufferProducer::getFrameTimestamps| + void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) override; + + // See |IGraphicBufferProducer::getUniqueId| + status_t getUniqueId(uint64_t* out_id) const override; + + // See |IGraphicBufferProducer::getConsumerUsage| + status_t getConsumerUsage(uint64_t* out_usage) const override; + + // Takes out the current producer as a binder parcelable object. Note that the + // producer must be disconnected to be exportable. After successful export, + // the producer queue can no longer be connected again. Returns NO_ERROR when + // takeout is successful and out_parcelable will hold the new parcelable + // object. Also note that out_parcelable cannot be NULL and must points to an + // invalid parcelable. + status_t TakeAsParcelable(dvr::ProducerQueueParcelable* out_parcelable); + + IBinder* onAsBinder() override; + +protected: + // See |IGraphicBufferProducer::exportToParcel| + status_t exportToParcel(Parcel* parcel) override; + +private: + using LocalHandle = pdx::LocalHandle; + + // Private constructor to force use of |Create|. + BufferHubProducer() {} + + static uint64_t genUniqueId() { + static std::atomic<uint32_t> counter{0}; + static uint64_t id = static_cast<uint64_t>(getpid()) << 32; + return id | counter++; + } + + // Allocate new buffer through BufferHub and add it into |queue_| for + // bookkeeping. + status_t AllocateBuffer(uint32_t width, uint32_t height, uint32_t layer_count, + PixelFormat format, uint64_t usage); + + // Remove a buffer via BufferHubRPC. + status_t RemoveBuffer(size_t slot); + + // Free all buffers which are owned by the prodcuer. Note that if graphic + // buffers are acquired by the consumer, we can't . + status_t FreeAllBuffers(); + + // Concreate implementation backed by BufferHubBuffer. + std::shared_ptr<dvr::ProducerQueue> queue_; + + // Mutex for thread safety. + std::mutex mutex_; + + // Connect client API, should be one of the NATIVE_WINDOW_API_* flags. + int connected_api_{kNoConnectedApi}; + + // |max_buffer_count_| sets the capacity of the underlying buffer queue. + int32_t max_buffer_count_{dvr::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}; + + // Sets how long dequeueBuffer or attachBuffer will block if a buffer or + // slot is not yet available. The timeout is stored in milliseconds. + int dequeue_timeout_ms_{dvr::BufferHubQueue::kNoTimeOut}; + + // |generation_number_| stores the current generation number of the attached + // producer. Any attempt to attach a buffer with a different generation + // number will fail. + // TOOD(b/38137191) Currently not used as we don't support + // IGraphicBufferProducer::detachBuffer. + uint32_t generation_number_{0}; + + // |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|. + // TODO(jwcai) The buffer allocated to a slot will also be replaced if the + // requested buffer usage or geometry differs from that of the buffer + // allocated to a slot. + struct BufferHubSlot : public BufferSlot { + BufferHubSlot() : mBufferProducer(nullptr), mIsReallocating(false) {} + // BufferSlot comes from android framework, using m prefix to comply with + // the name convention with the reset of data fields from BufferSlot. + std::shared_ptr<dvr::BufferProducer> mBufferProducer; + bool mIsReallocating; + }; + BufferHubSlot buffers_[dvr::BufferHubQueue::kMaxQueueCapacity]; + + // A uniqueId used by IGraphicBufferProducer interface. + const uint64_t unique_id_{genUniqueId()}; + + // A pending parcelable object which keeps the bufferhub channel alive. + dvr::ProducerQueueParcelable pending_producer_parcelable_; +}; + +} // namespace android + +#endif // ANDROID_GUI_BUFFERHUBPRODUCER_H_ diff --git a/libs/gui/include/gui/BufferItem.h b/libs/gui/include/gui/BufferItem.h index 55637a9be4..218bb424fb 100644 --- a/libs/gui/include/gui/BufferItem.h +++ b/libs/gui/include/gui/BufferItem.h @@ -17,6 +17,8 @@ #ifndef ANDROID_GUI_BUFFERITEM_H #define ANDROID_GUI_BUFFERITEM_H +#include <gui/HdrMetadata.h> + #include <ui/FenceTime.h> #include <ui/Rect.h> #include <ui/Region.h> @@ -86,6 +88,9 @@ class BufferItem : public Flattenable<BufferItem> { // dataSpace is format-dependent. android_dataspace mDataSpace; + // mHdrMetadata is the HDR metadata associated with this buffer slot. + HdrMetadata mHdrMetadata; + // mFrameNumber is the number of the queued frame for this slot. uint64_t mFrameNumber; @@ -122,6 +127,9 @@ class BufferItem : public Flattenable<BufferItem> { // Indicates that this BufferItem contains a stale buffer which has already // been released by the BufferQueue. bool mIsStale; + + // Indicates the API (NATIVE_WINDOW_API_xxx) that queues the buffer. + int mApi; }; } // namespace android diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h index d9c57757f5..a905610ee2 100644 --- a/libs/gui/include/gui/BufferItemConsumer.h +++ b/libs/gui/include/gui/BufferItemConsumer.h @@ -57,10 +57,6 @@ class BufferItemConsumer: public ConsumerBase ~BufferItemConsumer() override; - // set the name of the BufferItemConsumer that will be used to identify it in - // log messages. - void setName(const String8& name); - // setBufferFreedListener sets the listener object that will be notified // when an old buffer is being freed. void setBufferFreedListener(const wp<BufferFreedListener>& listener); diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h index ba5cbf7eb4..da952744f3 100644 --- a/libs/gui/include/gui/BufferQueue.h +++ b/libs/gui/include/gui/BufferQueue.h @@ -79,6 +79,12 @@ public: sp<IGraphicBufferConsumer>* outConsumer, bool consumerIsSurfaceFlinger = false); +#ifndef NO_BUFFERHUB + // Creates an IGraphicBufferProducer and IGraphicBufferConsumer pair backed by BufferHub. + static void createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer, + sp<IGraphicBufferConsumer>* outConsumer); +#endif + BufferQueue() = delete; // Create through createBufferQueue }; diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h index e9fc8fd1ea..366ced380b 100644 --- a/libs/gui/include/gui/ConsumerBase.h +++ b/libs/gui/include/gui/ConsumerBase.h @@ -89,6 +89,18 @@ public: // See IGraphicBufferConsumer::setDefaultBufferDataSpace status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace); + // See IGraphicBufferConsumer::setConsumerUsageBits + status_t setConsumerUsageBits(uint64_t usage); + + // See IGraphicBufferConsumer::setTransformHint + status_t setTransformHint(uint32_t hint); + + // See IGraphicBufferConsumer::setMaxAcquiredBufferCount + status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); + + // See IGraphicBufferConsumer::getSidebandStream + sp<NativeHandle> getSidebandStream() const; + // See IGraphicBufferConsumer::getOccupancyHistory status_t getOccupancyHistory(bool forceFlush, std::vector<OccupancyTracker::Segment>* outHistory); @@ -187,7 +199,7 @@ protected: // ConsumerBase::releaseBufferLocked. virtual status_t releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer, - EGLDisplay display, EGLSyncKHR eglFence); + EGLDisplay display = EGL_NO_DISPLAY, EGLSyncKHR eglFence = EGL_NO_SYNC_KHR); // returns true iff the slot still has the graphicBuffer in it. bool stillTracking(int slot, const sp<GraphicBuffer> graphicBuffer); diff --git a/libs/gui/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h index 58602bf321..d375611e5b 100644 --- a/libs/gui/include/gui/CpuConsumer.h +++ b/libs/gui/include/gui/CpuConsumer.h @@ -94,12 +94,6 @@ class CpuConsumer : public ConsumerBase CpuConsumer(const sp<IGraphicBufferConsumer>& bq, size_t maxLockedBuffers, bool controlledByApp = false); - virtual ~CpuConsumer(); - - // set the name of the CpuConsumer that will be used to identify it in - // log messages. - void setName(const String8& name); - // Gets the next graphics buffer from the producer and locks it for CPU use, // filling out the passed-in locked buffer structure with the native pointer // and metadata. Returns BAD_VALUE if no new buffer is available, and @@ -119,31 +113,39 @@ class CpuConsumer : public ConsumerBase private: // Maximum number of buffers that can be locked at a time - size_t mMaxLockedBuffers; - - status_t releaseAcquiredBufferLocked(size_t lockedIdx); - - virtual void freeBufferLocked(int slotIndex); + const size_t mMaxLockedBuffers; // Tracking for buffers acquired by the user struct AcquiredBuffer { + static constexpr uintptr_t kUnusedId = 0; + // Need to track the original mSlot index and the buffer itself because // the mSlot entry may be freed/reused before the acquired buffer is // released. int mSlot; sp<GraphicBuffer> mGraphicBuffer; - void *mBufferPointer; + uintptr_t mLockedBufferId; AcquiredBuffer() : mSlot(BufferQueue::INVALID_BUFFER_SLOT), - mBufferPointer(NULL) { + mLockedBufferId(kUnusedId) { + } + + void reset() { + mSlot = BufferQueue::INVALID_BUFFER_SLOT; + mGraphicBuffer.clear(); + mLockedBufferId = kUnusedId; } }; + + size_t findAcquiredBufferLocked(uintptr_t id) const; + + status_t lockBufferItem(const BufferItem& item, LockedBuffer* outBuffer) const; + Vector<AcquiredBuffer> mAcquiredBuffers; // Count of currently locked buffers size_t mCurrentLockedBuffers; - }; } // namespace android diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h index 75f2ccaaea..71ed3bf239 100644 --- a/libs/gui/include/gui/GLConsumer.h +++ b/libs/gui/include/gui/GLConsumer.h @@ -138,6 +138,10 @@ public: const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform, bool filtering); + // Scale the crop down horizontally or vertically such that it has the + // same aspect ratio as the buffer does. + static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight); + // getTimestamp retrieves the timestamp associated with the texture image // set by the most recent call to updateTexImage. // @@ -197,22 +201,9 @@ public: // buffer is ready to be read from. std::shared_ptr<FenceTime> getCurrentFenceTime() const; - // doGLFenceWait inserts a wait command into the OpenGL ES command stream - // to ensure that it is safe for future OpenGL ES commands to access the - // current texture buffer. - status_t doGLFenceWait() const; - - // set the name of the GLConsumer that will be used to identify it in - // log messages. - void setName(const String8& name); - - // These functions call the corresponding BufferQueue implementation - // so the refactoring can proceed smoothly - status_t setDefaultBufferFormat(PixelFormat defaultFormat); - status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace); + // setConsumerUsageBits overrides the ConsumerBase method to OR + // DEFAULT_USAGE_FLAGS to usage. status_t setConsumerUsageBits(uint64_t usage); - status_t setTransformHint(uint32_t hint); - status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); // detachFromContext detaches the GLConsumer from the calling thread's // current OpenGL ES context. This context must be the same as the context @@ -267,8 +258,6 @@ protected: return releaseBufferLocked(slot, graphicBuffer, mEglDisplay, eglFence); } - static bool isExternalFormat(PixelFormat format); - struct PendingRelease { PendingRelease() : isPending(false), currentTexture(-1), graphicBuffer(), display(nullptr), fence(nullptr) {} diff --git a/libs/gui/include/gui/HdrMetadata.h b/libs/gui/include/gui/HdrMetadata.h new file mode 100644 index 0000000000..9800602d6c --- /dev/null +++ b/libs/gui/include/gui/HdrMetadata.h @@ -0,0 +1,45 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <stdint.h> + +#include <system/graphics.h> +#include <utils/Flattenable.h> + +namespace android { + +struct HdrMetadata : public LightFlattenable<HdrMetadata> { + enum Type : uint32_t { + SMPTE2086 = 1 << 0, + CTA861_3 = 1 << 1, + }; + uint32_t validTypes{0}; + + android_smpte2086_metadata smpte2086{}; + android_cta861_3_metadata cta8613{}; + + // LightFlattenable + bool isFixedSize() const { return false; } + size_t getFlattenedSize() const; + status_t flatten(void* buffer, size_t size) const; + status_t unflatten(void const* buffer, size_t size); + + bool operator==(const HdrMetadata& rhs) const; +}; + +} // namespace android diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 039dc0d657..887654e05b 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -31,6 +31,7 @@ #include <ui/Region.h> #include <gui/FrameTimestamps.h> +#include <gui/HdrMetadata.h> #include <hidl/HybridInterface.h> #include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h> @@ -72,6 +73,14 @@ public: RELEASE_ALL_BUFFERS = 0x2, }; + enum { + // A parcelable magic indicates using Binder BufferQueue as transport + // backend. + USE_BUFFER_QUEUE = 0x62717565, // 'bque' + // A parcelable magic indicates using BufferHub as transport backend. + USE_BUFFER_HUB = 0x62687562, // 'bhub' + }; + // requestBuffer requests a new buffer for the given index. The server (i.e. // the IGraphicBufferProducer implementation) assigns the newly created // buffer to the given slot index, and the client is expected to mirror the @@ -354,6 +363,9 @@ public: const Region& getSurfaceDamage() const { return surfaceDamage; } void setSurfaceDamage(const Region& damage) { surfaceDamage = damage; } + const HdrMetadata& getHdrMetadata() const { return hdrMetadata; } + void setHdrMetadata(const HdrMetadata& metadata) { hdrMetadata = metadata; } + private: int64_t timestamp{0}; int isAutoTimestamp{0}; @@ -365,6 +377,7 @@ public: sp<Fence> fence; Region surfaceDamage; bool getFrameTimestamps{false}; + HdrMetadata hdrMetadata; }; struct QueueBufferOutput : public Flattenable<QueueBufferOutput> { @@ -599,6 +612,24 @@ public: // returned by querying the now deprecated // NATIVE_WINDOW_CONSUMER_USAGE_BITS attribute. virtual status_t getConsumerUsage(uint64_t* outUsage) const = 0; + + // Static method exports any IGraphicBufferProducer object to a parcel. It + // handles null producer as well. + static status_t exportToParcel(const sp<IGraphicBufferProducer>& producer, + Parcel* parcel); + + // Factory method that creates a new IBGP instance from the parcel. + static sp<IGraphicBufferProducer> createFromParcel(const Parcel* parcel); + +protected: + // Exports the current producer as a binder parcelable object. Note that the + // producer must be disconnected to be exportable. After successful export, + // the producer queue can no longer be connected again. Returns NO_ERROR + // when the export is successful and writes an implementation defined + // parcelable object into the parcel. For traditional Android BufferQueue, + // it writes a strong binder object; for BufferHub, it writes a + // ProducerQueueParcelable object. + virtual status_t exportToParcel(Parcel* parcel); }; // ---------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index b2267426a8..e40157206d 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -29,6 +29,8 @@ #include <ui/FrameStats.h> #include <ui/PixelFormat.h> +#include <ui/GraphicBuffer.h> +#include <ui/GraphicTypes.h> #include <vector> @@ -59,6 +61,11 @@ public: enum { eSynchronous = 0x01, eAnimation = 0x02, + + // Indicates that this transaction will likely result in a lot of layers being composed, and + // thus, SurfaceFlinger should wake-up earlier to avoid missing frame deadlines. In this + // case SurfaceFlinger will wake up at (sf vsync offset - debug.sf.early_phase_offset_ns) + eEarlyWakeup = 0x04 }; enum { @@ -159,20 +166,25 @@ public: virtual status_t setActiveConfig(const sp<IBinder>& display, int id) = 0; virtual status_t getDisplayColorModes(const sp<IBinder>& display, - Vector<android_color_mode_t>* outColorModes) = 0; - virtual android_color_mode_t getActiveColorMode(const sp<IBinder>& display) = 0; + Vector<ui::ColorMode>* outColorModes) = 0; + virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& display) = 0; virtual status_t setActiveColorMode(const sp<IBinder>& display, - android_color_mode_t colorMode) = 0; + ui::ColorMode colorMode) = 0; /* Capture the specified screen. requires READ_FRAME_BUFFER permission * This function will fail if there is a secure window on screen. */ - virtual status_t captureScreen(const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, - Rotation rotation = eRotateNone) = 0; + virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer, + Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, + int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, + Rotation rotation = eRotateNone) = 0; + + /** + * Capture a subtree of the layer hierarchy, potentially ignoring the root node. + */ + virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder, + sp<GraphicBuffer>* outBuffer, const Rect& sourceCrop, + float frameScale = 1.0, bool childrenOnly = false) = 0; /* Clears the frame statistics for animations. * @@ -226,6 +238,7 @@ public: SET_ACTIVE_CONFIG, CONNECT_DISPLAY, CAPTURE_SCREEN, + CAPTURE_LAYERS, CLEAR_ANIMATION_FRAME_STATS, GET_ANIMATION_FRAME_STATS, SET_POWER_MODE, diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h index 2c613ea8c5..8dfc99a4b7 100644 --- a/libs/gui/include/gui/ISurfaceComposerClient.h +++ b/libs/gui/include/gui/ISurfaceComposerClient.h @@ -41,7 +41,7 @@ public: eCursorWindow = 0x00002000, eFXSurfaceNormal = 0x00000000, - eFXSurfaceDim = 0x00020000, + eFXSurfaceColor = 0x00020000, eFXSurfaceMask = 0x000F0000, }; @@ -49,8 +49,8 @@ public: * Requires ACCESS_SURFACE_FLINGER permission */ virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags, const sp<IBinder>& parent, uint32_t windowType, - uint32_t ownerUid, sp<IBinder>* handle, + uint32_t flags, const sp<IBinder>& parent, int32_t windowType, + int32_t ownerUid, sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) = 0; /* diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h index 8453e043ef..92bd8c5b28 100644 --- a/libs/gui/include/gui/LayerDebugInfo.h +++ b/libs/gui/include/gui/LayerDebugInfo.h @@ -22,6 +22,7 @@ #include <ui/Region.h> #include <string> +#include <math/vec4.h> namespace android { @@ -52,7 +53,7 @@ public: int32_t mHeight = -1; Rect mCrop = Rect::INVALID_RECT; Rect mFinalCrop = Rect::INVALID_RECT; - float mAlpha = 0.f; + half4 mColor = half4(1.0_hf, 1.0_hf, 1.0_hf, 0.0_hf); uint32_t mFlags = 0; PixelFormat mPixelFormat = PIXEL_FORMAT_NONE; android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN; diff --git a/libs/gui/include/private/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 307c764702..788962e490 100644 --- a/libs/gui/include/private/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -25,6 +25,7 @@ #include <ui/Region.h> #include <ui/Rect.h> #include <gui/IGraphicBufferProducer.h> +#include <math/vec3.h> namespace android { @@ -59,7 +60,10 @@ struct layer_state_t { eGeometryAppliesWithResize = 0x00001000, eReparentChildren = 0x00002000, eDetachChildren = 0x00004000, - eRelativeLayerChanged = 0x00008000 + eRelativeLayerChanged = 0x00008000, + eReparent = 0x00010000, + eColorChanged = 0x00020000, + eDestroySurface = 0x00040000 }; layer_state_t() @@ -74,6 +78,7 @@ struct layer_state_t { matrix.dsdy = matrix.dtdx = 0.0f; } + void merge(const layer_state_t& other); status_t write(Parcel& output) const; status_t read(const Parcel& input); @@ -107,6 +112,10 @@ struct layer_state_t { sp<IBinder> relativeLayerHandle; + sp<IBinder> parentHandleForChild; + + half3 color; + // non POD must be last. see write/read Region transparentRegion; }; @@ -137,6 +146,7 @@ struct DisplayState { }; DisplayState(); + void merge(const DisplayState& other); uint32_t what; sp<IBinder> token; @@ -150,6 +160,20 @@ struct DisplayState { status_t read(const Parcel& input); }; +static inline +int compare_type(const ComposerState& lhs, const ComposerState& rhs) { + if (lhs.client < rhs.client) return -1; + if (lhs.client > rhs.client) return 1; + if (lhs.state.surface < rhs.state.surface) return -1; + if (lhs.state.surface > rhs.state.surface) return 1; + return 0; +} + +static inline +int compare_type(const DisplayState& lhs, const DisplayState& rhs) { + return compare_type(lhs.token, rhs.token); +} + }; // namespace android #endif // ANDROID_SF_LAYER_STATE_H diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 55dd6bf067..9aeafae198 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -17,10 +17,12 @@ #ifndef ANDROID_GUI_SURFACE_H #define ANDROID_GUI_SURFACE_H -#include <gui/IGraphicBufferProducer.h> #include <gui/BufferQueueDefs.h> +#include <gui/HdrMetadata.h> +#include <gui/IGraphicBufferProducer.h> #include <ui/ANativeObjectBase.h> +#include <ui/GraphicTypes.h> #include <ui/Region.h> #include <utils/Condition.h> @@ -214,6 +216,8 @@ private: int dispatchUnlockAndPost(va_list args); int dispatchSetSidebandStream(va_list args); int dispatchSetBuffersDataSpace(va_list args); + int dispatchSetBuffersSmpte2086Metadata(va_list args); + int dispatchSetBuffersCta8613Metadata(va_list args); int dispatchSetSurfaceDamage(va_list args); int dispatchSetSharedBufferMode(va_list args); int dispatchSetAutoRefresh(va_list args); @@ -242,7 +246,9 @@ protected: virtual int setBuffersTransform(uint32_t transform); virtual int setBuffersStickyTransform(uint32_t transform); virtual int setBuffersTimestamp(int64_t timestamp); - virtual int setBuffersDataSpace(android_dataspace dataSpace); + virtual int setBuffersDataSpace(ui::Dataspace dataSpace); + virtual int setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata); + virtual int setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata); virtual int setCrop(Rect const* rect); virtual int setUsage(uint64_t reqUsage); virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects); @@ -281,6 +287,10 @@ public: // detachNextBuffer, or attachBuffer call. status_t getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out); + ui::Dataspace getBuffersDataSpace(); + + static status_t attachAndQueueBuffer(Surface* surface, sp<GraphicBuffer> buffer); + protected: enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; @@ -331,9 +341,13 @@ protected: int64_t mTimestamp; // mDataSpace is the buffer dataSpace that will be used for the next buffer - // queue operation. It defaults to HAL_DATASPACE_UNKNOWN, which + // queue operation. It defaults to Dataspace::UNKNOWN, which // means that the buffer contains some type of color data. - android_dataspace mDataSpace; + ui::Dataspace mDataSpace; + + // mHdrMetadata is the HDR metadata that will be used for the next buffer + // queue operation. There is no HDR metadata by default. + HdrMetadata mHdrMetadata; // mCrop is the crop rectangle that will be used for the next buffer // that gets queued. It is set by calling setCrop. diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 145c0597bd..377fe68c41 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -19,6 +19,7 @@ #include <stdint.h> #include <sys/types.h> +#include <unordered_map> #include <binder/IBinder.h> @@ -28,17 +29,19 @@ #include <utils/threads.h> #include <ui/FrameStats.h> +#include <ui/GraphicTypes.h> #include <ui/PixelFormat.h> #include <gui/CpuConsumer.h> #include <gui/SurfaceControl.h> +#include <math/vec3.h> +#include <gui/LayerState.h> namespace android { // --------------------------------------------------------------------------- struct DisplayInfo; -class Composer; class HdrCapabilities; class ISurfaceComposerClient; class IGraphicBufferProducer; @@ -51,6 +54,7 @@ class SurfaceComposerClient : public RefBase friend class Composer; public: SurfaceComposerClient(); + SurfaceComposerClient(const sp<ISurfaceComposerClient>& client); SurfaceComposerClient(const sp<IGraphicBufferProducer>& parent); virtual ~SurfaceComposerClient(); @@ -85,13 +89,14 @@ public: // Gets the list of supported color modes for the given display static status_t getDisplayColorModes(const sp<IBinder>& display, - Vector<android_color_mode_t>* outColorModes); + Vector<ui::ColorMode>* outColorModes); // Gets the active color mode for the given display - static android_color_mode_t getActiveColorMode(const sp<IBinder>& display); + static ui::ColorMode getActiveColorMode(const sp<IBinder>& display); // Sets the active color mode for the given display - static status_t setActiveColorMode(const sp<IBinder>& display, android_color_mode_t colorMode); + static status_t setActiveColorMode(const sp<IBinder>& display, + ui::ColorMode colorMode); /* Triggers screen on/off or low power mode and waits for it to complete */ static void setDisplayPowerMode(const sp<IBinder>& display, int mode); @@ -107,8 +112,20 @@ public: PixelFormat format, // pixel-format desired uint32_t flags = 0, // usage flags SurfaceControl* parent = nullptr, // parent - uint32_t windowType = 0, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.) - uint32_t ownerUid = 0 // UID of the task + int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.) + int32_t ownerUid = -1 // UID of the task + ); + + status_t createSurfaceChecked( + const String8& name,// name of the surface + uint32_t w, // width in pixel + uint32_t h, // height in pixel + PixelFormat format, // pixel-format desired + sp<SurfaceControl>* outSurface, + uint32_t flags = 0, // usage flags + SurfaceControl* parent = nullptr, // parent + int32_t windowType = -1, // from WindowManager.java (STATUS_BAR, INPUT_METHOD, etc.) + int32_t ownerUid = -1 // UID of the task ); //! Create a virtual display @@ -121,157 +138,185 @@ public: //! Possible values for id are eDisplayIdMain and eDisplayIdHdmi. static sp<IBinder> getBuiltInDisplay(int32_t id); - // ------------------------------------------------------------------------ - // Composer parameters - // All composer parameters must be changed within a transaction - // several surfaces can be updated in one transaction, all changes are - // committed at once when the transaction is closed. - // closeGlobalTransaction() requires an IPC with the server. - - //! Open a composer transaction on all active SurfaceComposerClients. - static void openGlobalTransaction(); - - //! Close a composer transaction on all active SurfaceComposerClients. - static void closeGlobalTransaction(bool synchronous = false); - static status_t enableVSyncInjections(bool enable); static status_t injectVSync(nsecs_t when); - //! Flag the currently open transaction as an animation transaction. - static void setAnimationTransaction(); - - status_t hide(const sp<IBinder>& id); - status_t show(const sp<IBinder>& id); - status_t setFlags(const sp<IBinder>& id, uint32_t flags, uint32_t mask); - status_t setTransparentRegionHint(const sp<IBinder>& id, const Region& transparent); - status_t setLayer(const sp<IBinder>& id, int32_t layer); - status_t setRelativeLayer(const sp<IBinder>& id, - const sp<IBinder>& relativeTo, int32_t layer); - status_t setAlpha(const sp<IBinder>& id, float alpha=1.0f); - status_t setMatrix(const sp<IBinder>& id, float dsdx, float dtdx, float dtdy, float dsdy); - status_t setPosition(const sp<IBinder>& id, float x, float y); - status_t setSize(const sp<IBinder>& id, uint32_t w, uint32_t h); - status_t setCrop(const sp<IBinder>& id, const Rect& crop); - status_t setFinalCrop(const sp<IBinder>& id, const Rect& crop); - status_t setLayerStack(const sp<IBinder>& id, uint32_t layerStack); - status_t deferTransactionUntil(const sp<IBinder>& id, - const sp<IBinder>& handle, uint64_t frameNumber); - status_t deferTransactionUntil(const sp<IBinder>& id, - const sp<Surface>& handle, uint64_t frameNumber); - status_t reparentChildren(const sp<IBinder>& id, - const sp<IBinder>& newParentHandle); - status_t detachChildren(const sp<IBinder>& id); - status_t setOverrideScalingMode(const sp<IBinder>& id, - int32_t overrideScalingMode); - status_t setGeometryAppliesWithResize(const sp<IBinder>& id); + struct SCHash { + std::size_t operator()(const sp<SurfaceControl>& sc) const { + return std::hash<SurfaceControl *>{}(sc.get()); + } + }; + + class Transaction { + std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates; + SortedVector<DisplayState > mDisplayStates; + uint32_t mForceSynchronous = 0; + uint32_t mTransactionNestCount = 0; + bool mAnimation = false; + bool mEarlyWakeup = false; + + int mStatus = NO_ERROR; + + layer_state_t* getLayerState(const sp<SurfaceControl>& sc); + DisplayState& getDisplayState(const sp<IBinder>& token); + + public: + Transaction() = default; + virtual ~Transaction() = default; + Transaction(Transaction const& other); + + status_t apply(bool synchronous = false); + // Merge another transaction in to this one, clearing other + // as if it had been applied. + Transaction& merge(Transaction&& other); + Transaction& show(const sp<SurfaceControl>& sc); + Transaction& hide(const sp<SurfaceControl>& sc); + Transaction& setPosition(const sp<SurfaceControl>& sc, + float x, float y); + Transaction& setSize(const sp<SurfaceControl>& sc, + uint32_t w, uint32_t h); + Transaction& setLayer(const sp<SurfaceControl>& sc, + int32_t z); + + // Sets a Z order relative to the Surface specified by "relativeTo" but + // without becoming a full child of the relative. Z-ordering works exactly + // as if it were a child however. + // + // As a nod to sanity, only non-child surfaces may have a relative Z-order. + // + // This overrides any previous call and is overriden by any future calls + // to setLayer. + // + // If the relative is removed, the Surface will have no layer and be + // invisible, until the next time set(Relative)Layer is called. + Transaction& setRelativeLayer(const sp<SurfaceControl>& sc, + const sp<IBinder>& relativeTo, int32_t z); + Transaction& setFlags(const sp<SurfaceControl>& sc, + uint32_t flags, uint32_t mask); + Transaction& setTransparentRegionHint(const sp<SurfaceControl>& sc, + const Region& transparentRegion); + Transaction& setAlpha(const sp<SurfaceControl>& sc, + float alpha); + Transaction& setMatrix(const sp<SurfaceControl>& sc, + float dsdx, float dtdx, float dtdy, float dsdy); + Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop); + Transaction& setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop); + Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack); + // Defers applying any changes made in this transaction until the Layer + // identified by handle reaches the given frameNumber. If the Layer identified + // by handle is removed, then we will apply this transaction regardless of + // what frame number has been reached. + Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc, + const sp<IBinder>& handle, + uint64_t frameNumber); + // A variant of deferTransactionUntil which identifies the Layer we wait for by + // Surface instead of Handle. Useful for clients which may not have the + // SurfaceControl for some of their Surfaces. Otherwise behaves identically. + Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc, + const sp<Surface>& barrierSurface, + uint64_t frameNumber); + // Reparents all children of this layer to the new parent handle. + Transaction& reparentChildren(const sp<SurfaceControl>& sc, + const sp<IBinder>& newParentHandle); + + /// Reparents the current layer to the new parent handle. The new parent must not be null. + // This can be used instead of reparentChildren if the caller wants to + // only re-parent a specific child. + Transaction& reparent(const sp<SurfaceControl>& sc, + const sp<IBinder>& newParentHandle); + + Transaction& setColor(const sp<SurfaceControl>& sc, const half3& color); + + // Detaches all child surfaces (and their children recursively) + // from their SurfaceControl. + // The child SurfaceControls will not throw exceptions or return errors, + // but transactions will have no effect. + // The child surfaces will continue to follow their parent surfaces, + // and remain eligible for rendering, but their relative state will be + // frozen. We use this in the WindowManager, in app shutdown/relaunch + // scenarios, where the app would otherwise clean up its child Surfaces. + // Sometimes the WindowManager needs to extend their lifetime slightly + // in order to perform an exit animation or prevent flicker. + Transaction& detachChildren(const sp<SurfaceControl>& sc); + // Set an override scaling mode as documented in <system/window.h> + // the override scaling mode will take precedence over any client + // specified scaling mode. -1 will clear the override scaling mode. + Transaction& setOverrideScalingMode(const sp<SurfaceControl>& sc, + int32_t overrideScalingMode); + + // If the size changes in this transaction, all geometry updates specified + // in this transaction will not complete until a buffer of the new size + // arrives. As some elements normally apply immediately, this enables + // freezing the total geometry of a surface until a resize is completed. + Transaction& setGeometryAppliesWithResize(const sp<SurfaceControl>& sc); + + Transaction& destroySurface(const sp<SurfaceControl>& sc); + + status_t setDisplaySurface(const sp<IBinder>& token, + const sp<IGraphicBufferProducer>& bufferProducer); + + void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack); + + /* setDisplayProjection() defines the projection of layer stacks + * to a given display. + * + * - orientation defines the display's orientation. + * - layerStackRect defines which area of the window manager coordinate + * space will be used. + * - displayRect defines where on the display will layerStackRect be + * mapped to. displayRect is specified post-orientation, that is + * it uses the orientation seen by the end-user. + */ + void setDisplayProjection(const sp<IBinder>& token, + uint32_t orientation, + const Rect& layerStackRect, + const Rect& displayRect); + void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height); + void setAnimationTransaction(); + void setEarlyWakeup(); + }; status_t destroySurface(const sp<IBinder>& id); status_t clearLayerFrameStats(const sp<IBinder>& token) const; status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const; - static status_t clearAnimationFrameStats(); static status_t getAnimationFrameStats(FrameStats* outStats); static status_t getHdrCapabilities(const sp<IBinder>& display, HdrCapabilities* outCapabilities); - static status_t setDisplaySurface(const sp<IBinder>& token, - sp<IGraphicBufferProducer> bufferProducer); - static void setDisplayLayerStack(const sp<IBinder>& token, - uint32_t layerStack); - static void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height); - - /* setDisplayProjection() defines the projection of layer stacks - * to a given display. - * - * - orientation defines the display's orientation. - * - layerStackRect defines which area of the window manager coordinate - * space will be used. - * - displayRect defines where on the display will layerStackRect be - * mapped to. displayRect is specified post-orientation, that is - * it uses the orientation seen by the end-user. - */ static void setDisplayProjection(const sp<IBinder>& token, uint32_t orientation, const Rect& layerStackRect, const Rect& displayRect); + inline sp<ISurfaceComposerClient> getClient() { return mClient; } + private: virtual void onFirstRef(); - Composer& getComposer(); mutable Mutex mLock; status_t mStatus; sp<ISurfaceComposerClient> mClient; - Composer& mComposer; wp<IGraphicBufferProducer> mParent; }; // --------------------------------------------------------------------------- -class ScreenshotClient -{ +class ScreenshotClient { public: // if cropping isn't required, callers may pass in a default Rect, e.g.: // capture(display, producer, Rect(), reqWidth, ...); - static status_t capture( - const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform); - static status_t captureToBuffer( - const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, - uint32_t rotation, - sp<GraphicBuffer>* outbuffer); -private: - mutable sp<CpuConsumer> mCpuConsumer; - mutable sp<IGraphicBufferProducer> mProducer; - CpuConsumer::LockedBuffer mBuffer; - bool mHaveBuffer; - -public: - ScreenshotClient(); - ~ScreenshotClient(); - - // frees the previous screenshot and captures a new one - // if cropping isn't required, callers may pass in a default Rect, e.g.: - // update(display, Rect(), useIdentityTransform); - status_t update(const sp<IBinder>& display, - Rect sourceCrop, bool useIdentityTransform); - status_t update(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - bool useIdentityTransform); - status_t update(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform); - status_t update(const sp<IBinder>& display, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, uint32_t rotation); - - sp<CpuConsumer> getCpuConsumer() const; - - // release memory occupied by the screenshot - void release(); - - // pixels are valid until this object is freed or - // release() or update() is called - void const* getPixels() const; - - uint32_t getWidth() const; - uint32_t getHeight() const; - PixelFormat getFormat() const; - uint32_t getStride() const; - // size of allocated memory in bytes - size_t getSize() const; - android_dataspace getDataSpace() const; + static status_t capture(const sp<IBinder>& display, Rect sourceCrop, uint32_t reqWidth, + uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ, + bool useIdentityTransform, uint32_t rotation, + sp<GraphicBuffer>* outBuffer); + static status_t captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, float frameScale, + sp<GraphicBuffer>* outBuffer); + static status_t captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop, + float frameScale, sp<GraphicBuffer>* outBuffer); }; // --------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index c15209d32c..bd987dd638 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -29,6 +29,7 @@ #include <ui/Region.h> #include <gui/ISurfaceComposerClient.h> +#include <math/vec3.h> namespace android { @@ -43,6 +44,9 @@ class SurfaceComposerClient; class SurfaceControl : public RefBase { public: + static sp<SurfaceControl> readFromParcel(Parcel* parcel); + void writeToParcel(Parcel* parcel); + static bool isValid(const sp<SurfaceControl>& surface) { return (surface != 0) && surface->isValid(); } @@ -60,87 +64,6 @@ public: // disconnect any api that's connected void disconnect(); - status_t setLayerStack(uint32_t layerStack); - status_t setLayer(int32_t layer); - - // Sets a Z order relative to the Surface specified by "relativeTo" but - // without becoming a full child of the relative. Z-ordering works exactly - // as if it were a child however. - // - // As a nod to sanity, only non-child surfaces may have a relative Z-order. - // - // This overrides any previous and is overriden by any future calls - // to setLayer. - // - // If the relative dissapears, the Surface will have no layer and be - // invisible, until the next time set(Relative)Layer is called. - // - // TODO: This is probably a hack. Currently it exists only to work around - // some framework usage of the hidden APPLICATION_MEDIA_OVERLAY window type - // which allows inserting a window between a SurfaceView and it's main application - // window. However, since we are using child windows for the SurfaceView, but not using - // child windows elsewhere in O, the WindowManager can't set the layer appropriately. - // This is only used by the "TvInputService" and following the port of ViewRootImpl - // to child surfaces, we can then port this and remove this method. - status_t setRelativeLayer(const sp<IBinder>& relativeTo, int32_t layer); - status_t setPosition(float x, float y); - status_t setSize(uint32_t w, uint32_t h); - status_t hide(); - status_t show(); - status_t setFlags(uint32_t flags, uint32_t mask); - status_t setTransparentRegionHint(const Region& transparent); - status_t setAlpha(float alpha=1.0f); - - // Experimentarily it appears that the matrix transforms the - // on-screen rectangle and it's contents before the position is - // applied. - // - // TODO: Test with other combinations to find approximate transformation rules. - // - // For example: - // Layer sized (W,H) set to position (x,y) with matrix M=[-1, 0, 0, 1] (Horizontal flip) gives - // [((0, 0), (W, H)) x M] + (x,y) = ((-W, 0), (0, H)) + (x,y) = ((-W + x, y), (x, H+y)) - status_t setMatrix(float dsdx, float dtdx, float dtdy, float dsdy); - status_t setCrop(const Rect& crop); - status_t setFinalCrop(const Rect& crop); - - // If the size changes in this transaction, all geometry updates specified - // in this transaction will not complete until a buffer of the new size - // arrives. As some elements normally apply immediately, this enables - // freezing the total geometry of a surface until a resize is completed. - status_t setGeometryAppliesWithResize(); - - // Defers applying any changes made in this transaction until the Layer - // identified by handle reaches the given frameNumber. If the Layer identified - // by handle is removed, then we will apply this transaction regardless of - // what frame number has been reached. - status_t deferTransactionUntil(const sp<IBinder>& handle, uint64_t frameNumber); - - // A variant of deferTransactionUntil which identifies the Layer we wait for by - // Surface instead of Handle. Useful for clients which may not have the - // SurfaceControl for some of their Surfaces. Otherwise behaves identically. - status_t deferTransactionUntil(const sp<Surface>& barrier, uint64_t frameNumber); - - // Reparents all children of this layer to the new parent handle. - status_t reparentChildren(const sp<IBinder>& newParentHandle); - - // Detaches all child surfaces (and their children recursively) - // from their SurfaceControl. - // The child SurfaceControl's will not throw exceptions or return errors, - // but transactions will have no effect. - // The child surfaces will continue to follow their parent surfaces, - // and remain eligible for rendering, but their relative state will be - // frozen. We use this in the WindowManager, in app shutdown/relaunch - // scenarios, where the app would otherwise clean up its child Surfaces. - // Sometimes the WindowManager needs to extend their lifetime slightly - // in order to perform an exit animation or prevent flicker. - status_t detachChildren(); - - // Set an override scaling mode as documented in <system/window.h> - // the override scaling mode will take precedence over any client - // specified scaling mode. -1 will clear the override scaling mode. - status_t setOverrideScalingMode(int32_t overrideScalingMode); - static status_t writeSurfaceToParcel( const sp<SurfaceControl>& control, Parcel* parcel); @@ -151,6 +74,8 @@ public: status_t clearLayerFrameStats() const; status_t getLayerFrameStats(FrameStats* outStats) const; + sp<SurfaceComposerClient> getClient() const; + private: // can't be copied SurfaceControl& operator = (SurfaceControl& rhs); @@ -162,7 +87,8 @@ private: SurfaceControl( const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle, - const sp<IGraphicBufferProducer>& gbp); + const sp<IGraphicBufferProducer>& gbp, + bool owned); ~SurfaceControl(); @@ -175,6 +101,7 @@ private: sp<IGraphicBufferProducer> mGraphicBufferProducer; mutable Mutex mLock; mutable sp<Surface> mSurfaceData; + bool mOwned; }; }; // namespace android diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 908959ce1a..01e90e0eb8 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -49,3 +49,35 @@ cc_test { "libnativewindow" ], } + +// Build a separate binary for each source file to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE) +cc_test { + name: "libgui_separate_binary_test", + test_suites: ["device-tests"], + + clang: true, + cflags: [ + "-Wall", + "-Werror", + ], + + test_per_src: true, + srcs: [ + "SurfaceParcelable_test.cpp", + ], + + shared_libs: [ + "liblog", + "libbinder", + "libcutils", + "libgui", + "libui", + "libutils", + "libbufferhubqueue", // TODO(b/70046255): Remove these once BufferHub is integrated into libgui. + "libpdx_default_transport", + ], + + header_libs: [ + "libdvr_headers", + ], +} diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp index 588e54142f..36be7d9368 100644 --- a/libs/gui/tests/CpuConsumer_test.cpp +++ b/libs/gui/tests/CpuConsumer_test.cpp @@ -33,6 +33,7 @@ #include <utils/Mutex.h> #include <utils/Condition.h> +#include <thread> #include <vector> #define CPU_CONSUMER_TEST_FORMAT_RAW 0 #define CPU_CONSUMER_TEST_FORMAT_Y8 0 @@ -681,6 +682,70 @@ TEST_P(CpuConsumerTest, FromCpuLockMax) { } } +TEST_P(CpuConsumerTest, FromCpuInvalid) { + status_t err = mCC->lockNextBuffer(nullptr); + ASSERT_EQ(BAD_VALUE, err) << "lockNextBuffer did not fail"; + + CpuConsumer::LockedBuffer b; + err = mCC->unlockBuffer(b); + ASSERT_EQ(BAD_VALUE, err) << "unlockBuffer did not fail"; +} + +TEST_P(CpuConsumerTest, FromCpuMultiThread) { + CpuConsumerTestParams params = GetParam(); + ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, params.maxLockedBuffers + 1)); + + for (int i = 0; i < 10; i++) { + std::atomic<int> threadReadyCount(0); + auto lockAndUnlock = [&]() { + threadReadyCount++; + // busy wait + while (threadReadyCount < params.maxLockedBuffers + 1); + + CpuConsumer::LockedBuffer b; + status_t err = mCC->lockNextBuffer(&b); + if (err == NO_ERROR) { + usleep(1000); + err = mCC->unlockBuffer(b); + ASSERT_NO_ERROR(err, "Could not unlock buffer: "); + } else if (err == NOT_ENOUGH_DATA) { + // there are params.maxLockedBuffers+1 threads so one of the + // threads might get this error + } else { + FAIL() << "Could not lock buffer"; + } + }; + + // produce buffers + for (int j = 0; j < params.maxLockedBuffers + 1; j++) { + const int64_t time = 1234L; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time, &stride)); + } + + // spawn threads + std::vector<std::thread> threads; + for (int j = 0; j < params.maxLockedBuffers + 1; j++) { + threads.push_back(std::thread(lockAndUnlock)); + } + + // join threads + for (auto& thread : threads) { + thread.join(); + } + + // we produced N+1 buffers, but the threads might only consume N + CpuConsumer::LockedBuffer b; + if (mCC->lockNextBuffer(&b) == NO_ERROR) { + mCC->unlockBuffer(b); + } + + if (HasFatalFailure()) { + break; + } + } +} + CpuConsumerTestParams y8TestSets[] = { { 512, 512, 1, HAL_PIXEL_FORMAT_Y8}, { 512, 512, 3, HAL_PIXEL_FORMAT_Y8}, diff --git a/libs/gui/tests/GLTest.cpp b/libs/gui/tests/GLTest.cpp index 1739d9c7ca..a91552f7fe 100644 --- a/libs/gui/tests/GLTest.cpp +++ b/libs/gui/tests/GLTest.cpp @@ -22,6 +22,8 @@ namespace android { +using Transaction = SurfaceComposerClient::Transaction; + static int abs(int value) { return value > 0 ? value : -value; } @@ -68,10 +70,10 @@ void GLTest::SetUp() { ASSERT_TRUE(mSurfaceControl != NULL); ASSERT_TRUE(mSurfaceControl->isValid()); - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF)); - ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); - SurfaceComposerClient::closeGlobalTransaction(); + Transaction t; + ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7FFFFFFF) + .show(mSurfaceControl) + .apply()); sp<ANativeWindow> window = mSurfaceControl->getSurface(); mEglSurface = createWindowSurface(mEglDisplay, mGlConfig, window); diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp index dd23bd4cb2..a35cf11174 100644 --- a/libs/gui/tests/IGraphicBufferProducer_test.cpp +++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp @@ -42,6 +42,10 @@ #define TEST_CONTROLLED_BY_APP false #define TEST_PRODUCER_USAGE_BITS (0) +#ifndef USE_BUFFER_HUB_AS_BUFFER_QUEUE +#define USE_BUFFER_HUB_AS_BUFFER_QUEUE 0 +#endif + namespace android { namespace { @@ -66,9 +70,15 @@ namespace { const int QUEUE_BUFFER_INPUT_SCALING_MODE = 0; const int QUEUE_BUFFER_INPUT_TRANSFORM = 0; const sp<Fence> QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE; + + // Enums to control which IGraphicBufferProducer backend to test. + enum IGraphicBufferProducerTestCode { + USE_BUFFER_QUEUE_PRODUCER = 0, + USE_BUFFER_HUB_PRODUCER, + }; }; // namespace anonymous -class IGraphicBufferProducerTest : public ::testing::Test { +class IGraphicBufferProducerTest : public ::testing::TestWithParam<uint32_t> { protected: IGraphicBufferProducerTest() {} @@ -81,10 +91,27 @@ protected: mDC = new DummyConsumer; - BufferQueue::createBufferQueue(&mProducer, &mConsumer); + switch (GetParam()) { + case USE_BUFFER_QUEUE_PRODUCER: { + BufferQueue::createBufferQueue(&mProducer, &mConsumer); + break; + } + case USE_BUFFER_HUB_PRODUCER: { + BufferQueue::createBufferHubQueue(&mProducer, &mConsumer); + break; + } + default: { + // Should never reach here. + LOG_ALWAYS_FATAL("Invalid test params: %u", GetParam()); + break; + } + } // Test check: Can't connect producer if no consumer yet - ASSERT_EQ(NO_INIT, TryConnectProducer()); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. + ASSERT_EQ(NO_INIT, TryConnectProducer()); + } // Must connect consumer before producer connects will succeed. ASSERT_OK(mConsumer->consumerConnect(mDC, /*controlledByApp*/false)); @@ -229,7 +256,7 @@ protected: // accessible from test body sp<IGraphicBufferConsumer> mConsumer; }; -TEST_F(IGraphicBufferProducerTest, ConnectFirst_ReturnsError) { +TEST_P(IGraphicBufferProducerTest, ConnectFirst_ReturnsError) { IGraphicBufferProducer::QueueBufferOutput output; // NULL output returns BAD_VALUE @@ -247,7 +274,7 @@ TEST_F(IGraphicBufferProducerTest, ConnectFirst_ReturnsError) { // TODO: get a token from a dead process somehow } -TEST_F(IGraphicBufferProducerTest, ConnectAgain_ReturnsError) { +TEST_P(IGraphicBufferProducerTest, ConnectAgain_ReturnsError) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // Can't connect when there is already a producer connected @@ -259,20 +286,23 @@ TEST_F(IGraphicBufferProducerTest, ConnectAgain_ReturnsError) { ASSERT_OK(mConsumer->consumerDisconnect()); // Can't connect when IGBP is abandoned - EXPECT_EQ(NO_INIT, mProducer->connect(TEST_TOKEN, - TEST_API, - TEST_CONTROLLED_BY_APP, - &output)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. + EXPECT_EQ(NO_INIT, mProducer->connect(TEST_TOKEN, + TEST_API, + TEST_CONTROLLED_BY_APP, + &output)); + } } -TEST_F(IGraphicBufferProducerTest, Disconnect_Succeeds) { +TEST_P(IGraphicBufferProducerTest, Disconnect_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); ASSERT_OK(mProducer->disconnect(TEST_API)); } -TEST_F(IGraphicBufferProducerTest, Disconnect_ReturnsError) { +TEST_P(IGraphicBufferProducerTest, Disconnect_ReturnsError) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // Must disconnect with same API number @@ -283,7 +313,7 @@ TEST_F(IGraphicBufferProducerTest, Disconnect_ReturnsError) { // TODO: somehow kill mProducer so that this returns DEAD_OBJECT } -TEST_F(IGraphicBufferProducerTest, Query_Succeeds) { +TEST_P(IGraphicBufferProducerTest, Query_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int32_t value = -1; @@ -308,7 +338,7 @@ TEST_F(IGraphicBufferProducerTest, Query_Succeeds) { } -TEST_F(IGraphicBufferProducerTest, Query_ReturnsError) { +TEST_P(IGraphicBufferProducerTest, Query_ReturnsError) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // One past the end of the last 'query' enum value. Update this if we add more enums. @@ -334,14 +364,17 @@ TEST_F(IGraphicBufferProducerTest, Query_ReturnsError) { ASSERT_OK(mConsumer->consumerDisconnect()); // BQ was abandoned - EXPECT_EQ(NO_INIT, mProducer->query(NATIVE_WINDOW_FORMAT, &value)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. + EXPECT_EQ(NO_INIT, mProducer->query(NATIVE_WINDOW_FORMAT, &value)); + } // TODO: other things in window.h that are supported by Surface::query // but not by BufferQueue::query } // TODO: queue under more complicated situations not involving just a single buffer -TEST_F(IGraphicBufferProducerTest, Queue_Succeeds) { +TEST_P(IGraphicBufferProducerTest, Queue_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int dequeuedSlot = -1; @@ -371,16 +404,21 @@ TEST_F(IGraphicBufferProducerTest, Queue_Succeeds) { EXPECT_EQ(DEFAULT_WIDTH, output.width); EXPECT_EQ(DEFAULT_HEIGHT, output.height); EXPECT_EQ(DEFAULT_TRANSFORM_HINT, output.transformHint); + // Since queueBuffer was called exactly once - EXPECT_EQ(1u, output.numPendingBuffers); - EXPECT_EQ(2u, output.nextFrameNumber); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/70041889): BufferHubProducer need to support metadata: numPendingBuffers + EXPECT_EQ(1u, output.numPendingBuffers); + // TODO(b/70041952): BufferHubProducer need to support metadata: nextFrameNumber + EXPECT_EQ(2u, output.nextFrameNumber); + } } // Buffer was not in the dequeued state EXPECT_EQ(BAD_VALUE, mProducer->queueBuffer(dequeuedSlot, input, &output)); } -TEST_F(IGraphicBufferProducerTest, Queue_ReturnsError) { +TEST_P(IGraphicBufferProducerTest, Queue_ReturnsError) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // Invalid slot number @@ -463,15 +501,16 @@ TEST_F(IGraphicBufferProducerTest, Queue_ReturnsError) { ASSERT_OK(mConsumer->consumerDisconnect()); // The buffer queue has been abandoned. - { + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput(); IGraphicBufferProducer::QueueBufferOutput output; + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. EXPECT_EQ(NO_INIT, mProducer->queueBuffer(dequeuedSlot, input, &output)); } } -TEST_F(IGraphicBufferProducerTest, CancelBuffer_DoesntCrash) { +TEST_P(IGraphicBufferProducerTest, CancelBuffer_DoesntCrash) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int dequeuedSlot = -1; @@ -488,7 +527,7 @@ TEST_F(IGraphicBufferProducerTest, CancelBuffer_DoesntCrash) { mProducer->cancelBuffer(dequeuedSlot, dequeuedFence); } -TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) { +TEST_P(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int minUndequeuedBuffers; ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, @@ -540,7 +579,7 @@ TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) { ASSERT_OK(mProducer->setMaxDequeuedBufferCount(maxBuffers-1)); } -TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) { +TEST_P(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); int minUndequeuedBuffers; ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, @@ -578,12 +617,19 @@ TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) { ASSERT_OK(mConsumer->consumerDisconnect()); // Fail because the buffer queue was abandoned - EXPECT_EQ(NO_INIT, mProducer->setMaxDequeuedBufferCount(minBuffers)) - << "bufferCount: " << minBuffers; - + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/73267953): Make BufferHub honor producer and consumer connection. + EXPECT_EQ(NO_INIT, mProducer->setMaxDequeuedBufferCount(minBuffers)) + << "bufferCount: " << minBuffers; + } } -TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) { +TEST_P(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) { + if (GetParam() == USE_BUFFER_HUB_PRODUCER) { + // TODO(b/36724099): Add support for BufferHubProducer::setAsyncMode(true) + return; + } + ASSERT_OK(mConsumer->setMaxAcquiredBufferCount(1)) << "maxAcquire: " << 1; ASSERT_NO_FATAL_FAILURE(ConnectProducer()); ASSERT_OK(mProducer->setAsyncMode(true)) << "async mode: " << true; @@ -609,7 +655,7 @@ TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) { } } -TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Fails) { +TEST_P(IGraphicBufferProducerTest, SetAsyncMode_Fails) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); // Prerequisite to fail out a valid setBufferCount call { @@ -628,11 +674,13 @@ TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Fails) { ASSERT_OK(mConsumer->consumerDisconnect()); // Fail because the buffer queue was abandoned - EXPECT_EQ(NO_INIT, mProducer->setAsyncMode(false)) << "asyncMode: " - << false; + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/36724099): Make BufferHub honor producer and consumer connection. + EXPECT_EQ(NO_INIT, mProducer->setAsyncMode(false)) << "asyncMode: " << false; + } } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_dequeueBuffer) { int slot = -1; sp<Fence> fence; @@ -642,15 +690,18 @@ TEST_F(IGraphicBufferProducerTest, TEST_PRODUCER_USAGE_BITS, nullptr, nullptr)); } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_detachNextBuffer) { sp<Fence> fence; sp<GraphicBuffer> buffer; - ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/38137191): Implement BufferHubProducer::detachBuffer + ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence)); + } } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_requestBuffer) { ASSERT_NO_FATAL_FAILURE(ConnectProducer()); @@ -674,7 +725,7 @@ TEST_F(IGraphicBufferProducerTest, } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_detachBuffer) { int slot = -1; sp<Fence> fence; @@ -684,10 +735,13 @@ TEST_F(IGraphicBufferProducerTest, ASSERT_OK(mProducer->disconnect(TEST_API)); - ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/38137191): Implement BufferHubProducer::detachBuffer + ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot)); + } } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_queueBuffer) { int slot = -1; sp<Fence> fence; @@ -704,7 +758,7 @@ TEST_F(IGraphicBufferProducerTest, ASSERT_EQ(NO_INIT, mProducer->queueBuffer(slot, input, &output)); } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_cancelBuffer) { int slot = -1; sp<Fence> fence; @@ -717,7 +771,7 @@ TEST_F(IGraphicBufferProducerTest, ASSERT_EQ(NO_INIT, mProducer->cancelBuffer(slot, fence)); } -TEST_F(IGraphicBufferProducerTest, +TEST_P(IGraphicBufferProducerTest, DisconnectedProducerReturnsError_attachBuffer) { int slot = -1; sp<Fence> fence; @@ -725,11 +779,27 @@ TEST_F(IGraphicBufferProducerTest, setupDequeueRequestBuffer(&slot, &fence, &buffer); - ASSERT_OK(mProducer->detachBuffer(slot)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/38137191): Implement BufferHubProducer::detachBuffer + ASSERT_OK(mProducer->detachBuffer(slot)); + } ASSERT_OK(mProducer->disconnect(TEST_API)); - ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer)); + if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) { + // TODO(b/69981968): Implement BufferHubProducer::attachBuffer + ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer)); + } } +#if USE_BUFFER_HUB_AS_BUFFER_QUEUE +INSTANTIATE_TEST_CASE_P(IGraphicBufferProducerBackends, IGraphicBufferProducerTest, + ::testing::Values(USE_BUFFER_QUEUE_PRODUCER, USE_BUFFER_HUB_PRODUCER)); +#else +// TODO(b/70046255): Remove the #ifdef here and always tests both backends once BufferHubQueue can +// pass all existing libgui tests. +INSTANTIATE_TEST_CASE_P(IGraphicBufferProducerBackends, IGraphicBufferProducerTest, + ::testing::Values(USE_BUFFER_QUEUE_PRODUCER)); +#endif + } // namespace android diff --git a/libs/gui/tests/SurfaceParcelable_test.cpp b/libs/gui/tests/SurfaceParcelable_test.cpp new file mode 100644 index 0000000000..686dc82f3e --- /dev/null +++ b/libs/gui/tests/SurfaceParcelable_test.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "SurfaceParcelable_test" + +#include <gtest/gtest.h> + +#include <binder/IServiceManager.h> +#include <binder/ProcessState.h> +#include <gui/BufferHubProducer.h> +#include <gui/BufferQueue.h> +#include <gui/view/Surface.h> +#include <utils/Log.h> + +namespace android { + +static const String16 kTestServiceName = String16("SurfaceParcelableTestService"); +static const String16 kSurfaceName = String16("TEST_SURFACE"); +static const uint32_t kBufferWidth = 100; +static const uint32_t kBufferHeight = 1; +static const uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB; + +enum SurfaceParcelableTestServiceCode { + CREATE_BUFFER_QUEUE_SURFACE = IBinder::FIRST_CALL_TRANSACTION, + CREATE_BUFFER_HUB_SURFACE, +}; + +class SurfaceParcelableTestService : public BBinder { +public: + SurfaceParcelableTestService() { + // BufferQueue + BufferQueue::createBufferQueue(&mBufferQueueProducer, &mBufferQueueConsumer); + + // BufferHub + dvr::ProducerQueueConfigBuilder configBuilder; + mProducerQueue = dvr::ProducerQueue::Create(configBuilder.SetDefaultWidth(kBufferWidth) + .SetDefaultHeight(kBufferHeight) + .SetDefaultFormat(kBufferFormat) + .Build(), + dvr::UsagePolicy{}); + mBufferHubProducer = BufferHubProducer::Create(mProducerQueue); + } + + ~SurfaceParcelableTestService() = default; + + virtual status_t onTransact(uint32_t code, const Parcel& /*data*/, Parcel* reply, + uint32_t /*flags*/ = 0) { + switch (code) { + case CREATE_BUFFER_QUEUE_SURFACE: { + view::Surface surfaceShim; + surfaceShim.name = kSurfaceName; + surfaceShim.graphicBufferProducer = mBufferQueueProducer; + return surfaceShim.writeToParcel(reply); + } + case CREATE_BUFFER_HUB_SURFACE: { + view::Surface surfaceShim; + surfaceShim.name = kSurfaceName; + surfaceShim.graphicBufferProducer = mBufferHubProducer; + return surfaceShim.writeToParcel(reply); + } + default: + return UNKNOWN_TRANSACTION; + }; + } + +protected: + sp<IGraphicBufferProducer> mBufferQueueProducer; + sp<IGraphicBufferConsumer> mBufferQueueConsumer; + + std::shared_ptr<dvr::ProducerQueue> mProducerQueue; + sp<IGraphicBufferProducer> mBufferHubProducer; +}; + +static int runBinderServer() { + ProcessState::self()->startThreadPool(); + + sp<IServiceManager> sm = defaultServiceManager(); + sp<SurfaceParcelableTestService> service = new SurfaceParcelableTestService; + sm->addService(kTestServiceName, service, false); + + ALOGI("Binder server running..."); + + while (true) { + int stat, retval; + retval = wait(&stat); + if (retval == -1 && errno == ECHILD) { + break; + } + } + + ALOGI("Binder server exiting..."); + return 0; +} + +class SurfaceParcelableTest : public ::testing::TestWithParam<uint32_t> { +protected: + virtual void SetUp() { + mService = defaultServiceManager()->getService(kTestServiceName); + if (mService == nullptr) { + ALOGE("Failed to connect to the test service."); + return; + } + + ALOGI("Binder service is ready for client."); + } + + status_t GetSurface(view::Surface* surfaceShim) { + ALOGI("...Test: %d", GetParam()); + + uint32_t opCode = GetParam(); + Parcel data; + Parcel reply; + status_t error = mService->transact(opCode, data, &reply); + if (error != NO_ERROR) { + ALOGE("Failed to get surface over binder, error=%d.", error); + return error; + } + + error = surfaceShim->readFromParcel(&reply); + if (error != NO_ERROR) { + ALOGE("Failed to get surface from parcel, error=%d.", error); + return error; + } + + return NO_ERROR; + } + +private: + sp<IBinder> mService; +}; + +TEST_P(SurfaceParcelableTest, SendOverBinder) { + view::Surface surfaceShim; + EXPECT_EQ(GetSurface(&surfaceShim), NO_ERROR); + EXPECT_EQ(surfaceShim.name, kSurfaceName); + EXPECT_FALSE(surfaceShim.graphicBufferProducer == nullptr); +} + +INSTANTIATE_TEST_CASE_P(SurfaceBackends, SurfaceParcelableTest, + ::testing::Values(CREATE_BUFFER_QUEUE_SURFACE, CREATE_BUFFER_HUB_SURFACE)); + +} // namespace android + +int main(int argc, char** argv) { + pid_t pid = fork(); + if (pid == 0) { + android::ProcessState::self()->startThreadPool(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + + } else { + ALOGI("Test process pid: %d.", pid); + return android::runBinderServer(); + } +} diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index ca43c68f92..2c02ba657d 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -22,6 +22,7 @@ #include <binder/ProcessState.h> #include <configstore/Utils.h> #include <cutils/properties.h> +#include <inttypes.h> #include <gui/BufferItemConsumer.h> #include <gui/IDisplayEventConnection.h> #include <gui/IProducerListener.h> @@ -41,10 +42,16 @@ using namespace std::chrono_literals; // retrieve wide-color and hdr settings from configstore using namespace android::hardware::configstore; using namespace android::hardware::configstore::V1_0; +using ui::ColorMode; + +using Transaction = SurfaceComposerClient::Transaction; static bool hasWideColorDisplay = getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false); +static bool hasHdrDisplay = + getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false); + class FakeSurfaceComposer; class FakeProducerFrameEventHistory; @@ -52,7 +59,6 @@ static constexpr uint64_t NO_FRAME_INDEX = std::numeric_limits<uint64_t>::max(); class SurfaceTest : public ::testing::Test { protected: - SurfaceTest() { ProcessState::self()->startThreadPool(); } @@ -69,10 +75,10 @@ protected: ASSERT_TRUE(mSurfaceControl != NULL); ASSERT_TRUE(mSurfaceControl->isValid()); - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7fffffff)); - ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); - SurfaceComposerClient::closeGlobalTransaction(); + Transaction t; + ASSERT_EQ(NO_ERROR, t.setLayer(mSurfaceControl, 0x7fffffff) + .show(mSurfaceControl) + .apply()); mSurface = mSurfaceControl->getSurface(); ASSERT_TRUE(mSurface != NULL); @@ -87,6 +93,16 @@ protected: sp<SurfaceControl> mSurfaceControl; }; +TEST_F(SurfaceTest, CreateSurfaceReturnsErrorBadClient) { + mComposerClient->dispose(); + ASSERT_EQ(NO_INIT, mComposerClient->initCheck()); + + sp<SurfaceControl> sc; + status_t err = mComposerClient->createSurfaceChecked( + String8("Test Surface"), 32, 32, PIXEL_FORMAT_RGBA_8888, &sc, 0); + ASSERT_EQ(NO_INIT, err); +} + TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenVisible) { sp<ANativeWindow> anw(mSurface); int result = -123; @@ -114,14 +130,11 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { sp<ANativeWindow> anw(mSurface); // Verify the screenshot works with no protected buffers. - sp<IGraphicBufferProducer> producer; - sp<IGraphicBufferConsumer> consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1); sp<ISurfaceComposer> sf(ComposerService::getComposerService()); sp<IBinder> display(sf->getBuiltInDisplay( ISurfaceComposer::eDisplayIdMain)); - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), + sp<GraphicBuffer> outBuffer; + ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(), 64, 64, 0, 0x7fffffff, false)); ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(), @@ -152,7 +165,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { &buf)); ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1)); } - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), + ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(), 64, 64, 0, 0x7fffffff, false)); } @@ -295,6 +308,68 @@ TEST_F(SurfaceTest, GetWideColorSupport) { ASSERT_EQ(hasWideColorDisplay, supported); } +TEST_F(SurfaceTest, GetHdrSupport) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp<DummyConsumer> dummyConsumer(new DummyConsumer); + consumer->consumerConnect(dummyConsumer, false); + consumer->setConsumerName(String8("TestConsumer")); + + sp<Surface> surface = new Surface(producer); + sp<ANativeWindow> window(surface); + native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); + + bool supported; + status_t result = surface->getHdrSupport(&supported); + ASSERT_EQ(NO_ERROR, result); + + // NOTE: This is not a CTS test. + // This test verifies that when the BoardConfig TARGET_HAS_HDR_DISPLAY + // is TRUE, getHdrSupport is also true. + // TODO: Add check for an HDR color mode on the primary display. + ASSERT_EQ(hasHdrDisplay, supported); +} + +TEST_F(SurfaceTest, SetHdrMetadata) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp<DummyConsumer> dummyConsumer(new DummyConsumer); + consumer->consumerConnect(dummyConsumer, false); + consumer->setConsumerName(String8("TestConsumer")); + + sp<Surface> surface = new Surface(producer); + sp<ANativeWindow> window(surface); + native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); + + bool supported; + status_t result = surface->getHdrSupport(&supported); + ASSERT_EQ(NO_ERROR, result); + + if (!hasHdrDisplay || !supported) { + return; + } + const android_smpte2086_metadata smpte2086 = { + {0.680, 0.320}, + {0.265, 0.690}, + {0.150, 0.060}, + {0.3127, 0.3290}, + 100.0, + 0.1, + }; + const android_cta861_3_metadata cta861_3 = { + 78.0, + 62.0, + }; + int error = native_window_set_buffers_smpte2086_metadata(window.get(), &smpte2086); + ASSERT_EQ(error, NO_ERROR); + error = native_window_set_buffers_cta861_3_metadata(window.get(), &cta861_3); + ASSERT_EQ(error, NO_ERROR); +} + TEST_F(SurfaceTest, DynamicSetBufferCount) { sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; @@ -512,21 +587,26 @@ public: return NO_ERROR; } status_t getDisplayColorModes(const sp<IBinder>& /*display*/, - Vector<android_color_mode_t>* /*outColorModes*/) override { + Vector<ColorMode>* /*outColorModes*/) override { return NO_ERROR; } - android_color_mode_t getActiveColorMode(const sp<IBinder>& /*display*/) + ColorMode getActiveColorMode(const sp<IBinder>& /*display*/) override { - return HAL_COLOR_MODE_NATIVE; + return ColorMode::NATIVE; } status_t setActiveColorMode(const sp<IBinder>& /*display*/, - android_color_mode_t /*colorMode*/) override { return NO_ERROR; } + ColorMode /*colorMode*/) override { return NO_ERROR; } status_t captureScreen(const sp<IBinder>& /*display*/, - const sp<IGraphicBufferProducer>& /*producer*/, + sp<GraphicBuffer>* /*outBuffer*/, Rect /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/, int32_t /*minLayerZ*/, int32_t /*maxLayerZ*/, bool /*useIdentityTransform*/, Rotation /*rotation*/) override { return NO_ERROR; } + virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/, + sp<GraphicBuffer>* /*outBuffer*/, const Rect& /*sourceCrop*/, + float /*frameScale*/, bool /*childrenOnly*/) override { + return NO_ERROR; + } status_t clearAnimationFrameStats() override { return NO_ERROR; } status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override { return NO_ERROR; @@ -800,7 +880,7 @@ protected: (iOldFrame == NO_FRAME_INDEX) ? nullptr : &mFrames[iOldFrame]; FrameEvents* newFrame = &mFrames[iNewFrame]; - uint64_t nOldFrame = iOldFrame + 1; + uint64_t nOldFrame = (iOldFrame == NO_FRAME_INDEX) ? 0 : iOldFrame + 1; uint64_t nNewFrame = iNewFrame + 1; // Latch, Composite, and Release the frames in a plausible order. diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp index 5ed3d3bebb..d64dfd55be 100644 --- a/libs/gui/view/Surface.cpp +++ b/libs/gui/view/Surface.cpp @@ -45,10 +45,7 @@ status_t Surface::writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const { if (res != OK) return res; } - res = parcel->writeStrongBinder( - IGraphicBufferProducer::asBinder(graphicBufferProducer)); - - return res; + return IGraphicBufferProducer::exportToParcel(graphicBufferProducer, parcel); } status_t Surface::readFromParcel(const Parcel* parcel) { @@ -70,16 +67,7 @@ status_t Surface::readFromParcel(const Parcel* parcel, bool nameAlreadyRead) { } } - sp<IBinder> binder; - - res = parcel->readNullableStrongBinder(&binder); - if (res != OK) { - ALOGE("%s: Can't read strong binder", __FUNCTION__); - return res; - } - - graphicBufferProducer = interface_cast<IGraphicBufferProducer>(binder); - + graphicBufferProducer = IGraphicBufferProducer::createFromParcel(parcel); return OK; } |