Merge "Add libprocessgroup dependency and fix sched_policy include"
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 7dcc4a1..99f3739 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -171,7 +171,7 @@
chmod 0666 /sys/kernel/tracing/per_cpu/cpu5/trace
chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu6/trace
chmod 0666 /sys/kernel/tracing/per_cpu/cpu6/trace
- chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu6/trace
+ chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu7/trace
chmod 0666 /sys/kernel/tracing/per_cpu/cpu7/trace
chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu8/trace
chmod 0666 /sys/kernel/tracing/per_cpu/cpu8/trace
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index cfd2b40..214559d 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -774,7 +774,8 @@
AKEYCODE_THUMBS_UP = 286,
/** Thumbs down key. Apps can use this to let user downvote content. */
AKEYCODE_THUMBS_DOWN = 287,
- /** Consumed by system to switch current viewer profile. */
+ /** Used to switch current account that is consuming content.
+ * May be consumed by system to switch current viewer profile. */
AKEYCODE_PROFILE_SWITCH = 288
// NOTE: If you add a new keycode here you must also add it to several other files.
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 7357ba9..ad2dc14 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -66,7 +66,8 @@
virtual void setTransactionState(const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
- const InputWindowCommands& commands) {
+ const InputWindowCommands& commands,
+ int64_t desiredPresentTime) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -83,6 +84,7 @@
data.writeUint32(flags);
data.writeStrongBinder(applyToken);
commands.write(data);
+ data.writeInt64(desiredPresentTime);
remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
}
@@ -693,6 +695,42 @@
}
return err;
}
+
+ virtual status_t cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
+ int32_t* outBufferId) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+
+ data.writeStrongBinder(token);
+ if (buffer) {
+ data.writeBool(true);
+ data.write(*buffer);
+ } else {
+ data.writeBool(false);
+ }
+
+ status_t result = remote()->transact(BnSurfaceComposer::CACHE_BUFFER, data, &reply);
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ int32_t id = -1;
+ result = reply.readInt32(&id);
+ if (result == NO_ERROR) {
+ *outBufferId = id;
+ }
+ return result;
+ }
+
+ virtual status_t uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+
+ data.writeStrongBinder(token);
+ data.writeInt32(bufferId);
+
+ return remote()->transact(BnSurfaceComposer::UNCACHE_BUFFER, data, &reply);
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -748,7 +786,10 @@
sp<IBinder> applyToken = data.readStrongBinder();
InputWindowCommands inputWindowCommands;
inputWindowCommands.read(data);
- setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands);
+
+ int64_t desiredPresentTime = data.readInt64();
+ setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands,
+ desiredPresentTime);
return NO_ERROR;
}
case BOOT_FINISHED: {
@@ -1131,6 +1172,48 @@
}
return error;
}
+ case CACHE_BUFFER: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> token;
+ status_t result = data.readStrongBinder(&token);
+ if (result != NO_ERROR) {
+ ALOGE("cache buffer failure in reading token: %d", result);
+ return result;
+ }
+
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ if (data.readBool()) {
+ result = data.read(*buffer);
+ if (result != NO_ERROR) {
+ ALOGE("cache buffer failure in reading buffer: %d", result);
+ return result;
+ }
+ }
+ int32_t bufferId = -1;
+ status_t error = cacheBuffer(token, buffer, &bufferId);
+ if (error == NO_ERROR) {
+ reply->writeInt32(bufferId);
+ }
+ return error;
+ }
+ case UNCACHE_BUFFER: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> token;
+ status_t result = data.readStrongBinder(&token);
+ if (result != NO_ERROR) {
+ ALOGE("uncache buffer failure in reading token: %d", result);
+ return result;
+ }
+
+ int32_t bufferId = -1;
+ result = data.readInt32(&bufferId);
+ if (result != NO_ERROR) {
+ ALOGE("uncache buffer failure in reading buffer id: %d", result);
+ return result;
+ }
+
+ return uncacheBuffer(token, bufferId);
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index e5170ab..40b55fa 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -94,6 +94,9 @@
}
}
+ output.writeStrongBinder(cachedBuffer.token);
+ output.writeInt32(cachedBuffer.bufferId);
+
return NO_ERROR;
}
@@ -164,6 +167,9 @@
listenerCallbacks.emplace_back(listener, callbackIds);
}
+ cachedBuffer.token = input.readStrongBinder();
+ cachedBuffer.bufferId = input.readInt32();
+
return NO_ERROR;
}
@@ -372,6 +378,10 @@
}
#endif
+ if (other.what & eCachedBufferChanged) {
+ what |= eCachedBufferChanged;
+ cachedBuffer = other.cachedBuffer;
+ }
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
"other.what=0x%" PRIu64 " what=0x%" PRIu64,
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index e3ee511..a82054b 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -159,11 +159,12 @@
// ---------------------------------------------------------------------------
-SurfaceComposerClient::Transaction::Transaction(const Transaction& other) :
- mForceSynchronous(other.mForceSynchronous),
- mTransactionNestCount(other.mTransactionNestCount),
- mAnimation(other.mAnimation),
- mEarlyWakeup(other.mEarlyWakeup) {
+SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
+ : mForceSynchronous(other.mForceSynchronous),
+ mTransactionNestCount(other.mTransactionNestCount),
+ mAnimation(other.mAnimation),
+ mEarlyWakeup(other.mEarlyWakeup),
+ mDesiredPresentTime(other.mDesiredPresentTime) {
mDisplayStates = other.mDisplayStates;
mComposerStates = other.mComposerStates;
mInputWindowCommands = other.mInputWindowCommands;
@@ -218,7 +219,7 @@
s.state.parentHandleForChild = nullptr;
composerStates.add(s);
- sf->setTransactionState(composerStates, displayStates, 0, nullptr, {});
+ sf->setTransactionState(composerStates, displayStates, 0, nullptr, {}, -1);
}
status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
@@ -284,7 +285,8 @@
mEarlyWakeup = false;
sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
- sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands);
+ sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands,
+ mDesiredPresentTime);
mInputWindowCommands.clear();
mStatus = NO_ERROR;
return NO_ERROR;
@@ -658,6 +660,21 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCachedBuffer(
+ const sp<SurfaceControl>& sc, int32_t bufferId) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->what |= layer_state_t::eCachedBufferChanged;
+ s->cachedBuffer.token = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ s->cachedBuffer.bufferId = bufferId;
+
+ registerSurfaceControlForCallback(sc);
+ return *this;
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAcquireFence(
const sp<SurfaceControl>& sc, const sp<Fence>& fence) {
layer_state_t* s = getLayerState(sc);
@@ -742,6 +759,12 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesiredPresentTime(
+ nsecs_t desiredPresentTime) {
+ mDesiredPresentTime = desiredPresentTime;
+ return *this;
+}
+
SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
@@ -1049,6 +1072,26 @@
// ----------------------------------------------------------------------------
+status_t SurfaceComposerClient::cacheBuffer(const sp<GraphicBuffer>& buffer, int32_t* outBufferId) {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ if (buffer == nullptr || outBufferId == nullptr) {
+ return BAD_VALUE;
+ }
+ return sf->cacheBuffer(IInterface::asBinder(TransactionCompletedListener::getIInstance()),
+ buffer, outBufferId);
+}
+
+status_t SurfaceComposerClient::uncacheBuffer(int32_t bufferId) {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ if (bufferId < 0) {
+ return BAD_VALUE;
+ }
+ return sf->uncacheBuffer(IInterface::asBinder(TransactionCompletedListener::getIInstance()),
+ bufferId);
+}
+
+// ----------------------------------------------------------------------------
+
status_t SurfaceComposerClient::enableVSyncInjections(bool enable) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
return sf->enableVSyncInjections(enable);
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 9812e1c..418d5fb 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -116,7 +116,8 @@
virtual void setTransactionState(const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
- const InputWindowCommands& inputWindowCommands) = 0;
+ const InputWindowCommands& inputWindowCommands,
+ int64_t desiredPresentTime) = 0;
/* signal that we're done booting.
* Requires ACCESS_SURFACE_FLINGER permission
@@ -315,6 +316,11 @@
* Requires the ACCESS_SURFACE_FLINGER permission.
*/
virtual status_t getProtectedContentSupport(bool* outSupported) const = 0;
+
+ virtual status_t cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
+ int32_t* outBufferId) = 0;
+
+ virtual status_t uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) = 0;
};
// ----------------------------------------------------------------------------
@@ -357,6 +363,8 @@
SET_DISPLAY_CONTENT_SAMPLING_ENABLED,
GET_DISPLAYED_CONTENT_SAMPLE,
GET_PROTECTED_CONTENT_SUPPORT,
+ CACHE_BUFFER,
+ UNCACHE_BUFFER,
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index e7564f5..af31420 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -84,6 +84,7 @@
eInputInfoChanged = 0x40000000,
eCornerRadiusChanged = 0x80000000,
eFrameChanged = 0x1'00000000,
+ eCachedBufferChanged = 0x2'00000000,
};
layer_state_t()
@@ -125,6 +126,10 @@
float dtdy{0};
float dsdy{0};
};
+ struct cached_buffer_t {
+ sp<IBinder> token = nullptr;
+ int32_t bufferId = -1;
+ };
sp<IBinder> surface;
uint64_t what;
float x;
@@ -173,6 +178,8 @@
#ifndef NO_INPUT
InputWindowInfo inputInfo;
#endif
+
+ cached_buffer_t cachedBuffer;
};
struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 9a4f7a0..db315c2 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -158,6 +158,12 @@
static void doDropReferenceTransaction(const sp<IBinder>& handle,
const sp<ISurfaceComposerClient>& client);
+ // Caches a buffer with the ISurfaceComposer so the buffer does not need to be resent across
+ // processes
+ static status_t cacheBuffer(const sp<GraphicBuffer>& buffer, int32_t* outBufferId);
+ // Uncaches a buffer set by cacheBuffer
+ static status_t uncacheBuffer(int32_t bufferId);
+
// ------------------------------------------------------------------------
// surface creation / destruction
@@ -243,6 +249,18 @@
bool mAnimation = false;
bool mEarlyWakeup = false;
+ // mDesiredPresentTime is the time in nanoseconds that the client would like the transaction
+ // to be presented. When it is not possible to present at exactly that time, it will be
+ // presented after the time has passed.
+ //
+ // Desired present times that are more than 1 second in the future may be ignored.
+ // When a desired present time has already passed, the transaction will be presented as soon
+ // as possible.
+ //
+ // Transactions from the same process are presented in the same order that they are applied.
+ // The desired present time does not affect this ordering.
+ int64_t mDesiredPresentTime = -1;
+
InputWindowCommands mInputWindowCommands;
int mStatus = NO_ERROR;
@@ -323,6 +341,7 @@
Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop);
Transaction& setFrame(const sp<SurfaceControl>& sc, const Rect& frame);
Transaction& setBuffer(const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer);
+ Transaction& setCachedBuffer(const sp<SurfaceControl>& sc, int32_t bufferId);
Transaction& setAcquireFence(const sp<SurfaceControl>& sc, const sp<Fence>& fence);
Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace);
Transaction& setHdrMetadata(const sp<SurfaceControl>& sc, const HdrMetadata& hdrMetadata);
@@ -331,6 +350,7 @@
Transaction& setApi(const sp<SurfaceControl>& sc, int32_t api);
Transaction& setSidebandStream(const sp<SurfaceControl>& sc,
const sp<NativeHandle>& sidebandStream);
+ Transaction& setDesiredPresentTime(nsecs_t desiredPresentTime);
Transaction& addTransactionCompletedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext);
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 7fc69ff..ac97733 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -489,5 +489,13 @@
toSurface->expectMotionEvent(AMOTION_EVENT_ACTION_UP, 1, 1);
fromSurface->expectNoMotionEvent(AMOTION_EVENT_ACTION_UP);
}
+
+TEST_F(InputSurfacesTest, input_respects_outscreen) {
+ std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+ surface->showAt(-1, -1);
+
+ injectTap(0, 0);
+ surface->expectTap(1, 1);
+}
}
}
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 2d773f2..259ef9f 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -556,7 +556,9 @@
void setTransactionState(const Vector<ComposerState>& /*state*/,
const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
const sp<IBinder>& /*applyToken*/,
- const InputWindowCommands& /*inputWindowCommands*/) override {}
+ const InputWindowCommands& /*inputWindowCommands*/,
+ int64_t /*desiredPresentTime*/) override {}
+
void bootFinished() override {}
bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& /*surface*/) const override {
@@ -658,6 +660,12 @@
status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; }
status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; }
+ status_t cacheBuffer(const sp<IBinder>& /*token*/, const sp<GraphicBuffer>& /*buffer*/,
+ int32_t* /*outBufferId*/) {
+ return NO_ERROR;
+ }
+ status_t uncacheBuffer(const sp<IBinder>& /*token*/, int32_t /*bufferId*/) { return NO_ERROR; }
+
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 2915bb8..f57bf9c 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -1280,7 +1280,7 @@
std::lock_guard<std::mutex> lock(mMutex);
mCondition.wait(mMutex,
- [&]() REQUIRES(mMutex) { return !mQueue.empty() && !mRunning; });
+ [&]() REQUIRES(mMutex) { return !mQueue.empty() || !mRunning; });
if (!mRunning) {
// if mRunning is false, then FlushTracer is being destroyed, so
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index d089bf6..74450d7 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -60,7 +60,9 @@
"Fence.cpp",
"FenceTime.cpp",
"FrameStats.cpp",
+ "Gralloc.cpp",
"Gralloc2.cpp",
+ "Gralloc3.cpp",
"GraphicBuffer.cpp",
"GraphicBufferAllocator.cpp",
"GraphicBufferMapper.cpp",
@@ -68,6 +70,7 @@
"PixelFormat.cpp",
"Rect.cpp",
"Region.cpp",
+ "Size.cpp",
"Transform.cpp",
"UiConfig.cpp",
],
@@ -79,9 +82,11 @@
shared_libs: [
"android.frameworks.bufferhub@1.0",
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
+ "android.hardware.graphics.mapper@3.0",
"android.hardware.configstore@1.0",
"android.hardware.configstore-utils",
"libbase",
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/libs/ui/Gralloc.cpp
similarity index 67%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to libs/ui/Gralloc.cpp
index e6ac6bf..8e09a13 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/libs/ui/Gralloc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2016 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.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#define LOG_TAG "Gralloc"
+
+#include <ui/Gralloc.h>
namespace android {
-namespace mock {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+GrallocMapper::~GrallocMapper() {}
-} // namespace mock
+GrallocAllocator::~GrallocAllocator() {}
+
} // namespace android
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index 20f27c5..ea7321e 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -27,9 +27,15 @@
#include <sync/sync.h>
#pragma clang diagnostic pop
-namespace android {
+using android::hardware::graphics::allocator::V2_0::IAllocator;
+using android::hardware::graphics::common::V1_1::BufferUsage;
+using android::hardware::graphics::common::V1_1::PixelFormat;
+using android::hardware::graphics::mapper::V2_0::BufferDescriptor;
+using android::hardware::graphics::mapper::V2_0::Error;
+using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+using android::hardware::graphics::mapper::V2_1::IMapper;
-namespace Gralloc2 {
+namespace android {
namespace {
@@ -59,17 +65,26 @@
return valid11UsageBits;
}
+static inline IMapper::Rect sGralloc2Rect(const Rect& rect) {
+ IMapper::Rect outRect{};
+ outRect.left = rect.left;
+ outRect.top = rect.top;
+ outRect.width = rect.width();
+ outRect.height = rect.height();
+ return outRect;
+}
+
} // anonymous namespace
-void Mapper::preload() {
+void Gralloc2Mapper::preload() {
android::hardware::preloadPassthroughService<hardware::graphics::mapper::V2_0::IMapper>();
}
-Mapper::Mapper()
-{
+Gralloc2Mapper::Gralloc2Mapper() {
mMapper = hardware::graphics::mapper::V2_0::IMapper::getService();
if (mMapper == nullptr) {
- LOG_ALWAYS_FATAL("gralloc-mapper is missing");
+ ALOGW("mapper 2.x is not supported");
+ return;
}
if (mMapper->isRemote()) {
LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
@@ -79,30 +94,37 @@
mMapperV2_1 = IMapper::castFrom(mMapper);
}
-Gralloc2::Error Mapper::validateBufferDescriptorInfo(
- const IMapper::BufferDescriptorInfo& descriptorInfo) const {
+bool Gralloc2Mapper::isSupported() const {
+ return mMapper != nullptr;
+}
+
+status_t Gralloc2Mapper::validateBufferDescriptorInfo(
+ IMapper::BufferDescriptorInfo* descriptorInfo) const {
uint64_t validUsageBits = getValid10UsageBits();
if (mMapperV2_1 != nullptr) {
validUsageBits = validUsageBits | getValid11UsageBits();
}
- if (descriptorInfo.usage & ~validUsageBits) {
+ if (descriptorInfo->usage & ~validUsageBits) {
ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64,
- descriptorInfo.usage & ~validUsageBits);
- return Error::BAD_VALUE;
+ descriptorInfo->usage & ~validUsageBits);
+ return BAD_VALUE;
}
- return Error::NONE;
+ return NO_ERROR;
}
-Error Mapper::createDescriptor(
- const IMapper::BufferDescriptorInfo& descriptorInfo,
- BufferDescriptor* outDescriptor) const
-{
- Error error = validateBufferDescriptorInfo(descriptorInfo);
- if (error != Error::NONE) {
- return error;
+status_t Gralloc2Mapper::createDescriptor(void* bufferDescriptorInfo,
+ void* outBufferDescriptor) const {
+ IMapper::BufferDescriptorInfo* descriptorInfo =
+ static_cast<IMapper::BufferDescriptorInfo*>(bufferDescriptorInfo);
+ BufferDescriptor* outDescriptor = static_cast<BufferDescriptor*>(outBufferDescriptor);
+
+ status_t status = validateBufferDescriptorInfo(descriptorInfo);
+ if (status != NO_ERROR) {
+ return status;
}
+ Error error;
auto hidl_cb = [&](const auto& tmpError, const auto& tmpDescriptor)
{
error = tmpError;
@@ -115,24 +137,23 @@
hardware::Return<void> ret;
if (mMapperV2_1 != nullptr) {
- ret = mMapperV2_1->createDescriptor_2_1(descriptorInfo, hidl_cb);
+ ret = mMapperV2_1->createDescriptor_2_1(*descriptorInfo, hidl_cb);
} else {
const hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo info = {
- descriptorInfo.width,
- descriptorInfo.height,
- descriptorInfo.layerCount,
- static_cast<hardware::graphics::common::V1_0::PixelFormat>(descriptorInfo.format),
- descriptorInfo.usage,
+ descriptorInfo->width,
+ descriptorInfo->height,
+ descriptorInfo->layerCount,
+ static_cast<hardware::graphics::common::V1_0::PixelFormat>(descriptorInfo->format),
+ descriptorInfo->usage,
};
ret = mMapper->createDescriptor(info, hidl_cb);
}
- return (ret.isOk()) ? error : kTransactionError;
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
}
-Error Mapper::importBuffer(const hardware::hidl_handle& rawHandle,
- buffer_handle_t* outBufferHandle) const
-{
+status_t Gralloc2Mapper::importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const {
Error error;
auto ret = mMapper->importBuffer(rawHandle,
[&](const auto& tmpError, const auto& tmpBuffer)
@@ -145,11 +166,10 @@
*outBufferHandle = static_cast<buffer_handle_t>(tmpBuffer);
});
- return (ret.isOk()) ? error : kTransactionError;
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
}
-void Mapper::freeBuffer(buffer_handle_t bufferHandle) const
-{
+void Gralloc2Mapper::freeBuffer(buffer_handle_t bufferHandle) const {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
auto ret = mMapper->freeBuffer(buffer);
@@ -158,23 +178,29 @@
buffer, error);
}
-Error Mapper::validateBufferSize(buffer_handle_t bufferHandle,
- const IMapper::BufferDescriptorInfo& descriptorInfo,
- uint32_t stride) const
-{
+status_t Gralloc2Mapper::validateBufferSize(buffer_handle_t bufferHandle, uint32_t width,
+ uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const {
if (mMapperV2_1 == nullptr) {
- return Error::NONE;
+ return NO_ERROR;
}
+ IMapper::BufferDescriptorInfo descriptorInfo = {};
+ descriptorInfo.width = width;
+ descriptorInfo.height = height;
+ descriptorInfo.layerCount = layerCount;
+ descriptorInfo.format = static_cast<hardware::graphics::common::V1_1::PixelFormat>(format);
+ descriptorInfo.usage = usage;
+
auto buffer = const_cast<native_handle_t*>(bufferHandle);
auto ret = mMapperV2_1->validateBufferSize(buffer, descriptorInfo, stride);
- return (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError;
+ return static_cast<status_t>((ret.isOk()) ? static_cast<Error>(ret) : kTransactionError);
}
-void Mapper::getTransportSize(buffer_handle_t bufferHandle,
- uint32_t* outNumFds, uint32_t* outNumInts) const
-{
+void Gralloc2Mapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const {
*outNumFds = uint32_t(bufferHandle->numFds);
*outNumInts = uint32_t(bufferHandle->numInts);
@@ -195,19 +221,17 @@
*outNumInts = tmpNumInts;
});
- if (!ret.isOk()) {
- error = kTransactionError;
- }
- ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d",
- buffer, error);
+ error = (ret.isOk()) ? error : kTransactionError;
+
+ ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d", buffer, error);
}
-Error Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage,
- const IMapper::Rect& accessRegion,
- int acquireFence, void** outData) const
-{
+status_t Gralloc2Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData) const {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ IMapper::Rect accessRegion = sGralloc2Rect(bounds);
+
// put acquireFence in a hidl_handle
hardware::hidl_handle acquireFenceHandle;
NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
@@ -234,15 +258,19 @@
close(acquireFence);
}
- return (ret.isOk()) ? error : kTransactionError;
+ error = (ret.isOk()) ? error : kTransactionError;
+
+ ALOGW_IF(error != Error::NONE, "lock(%p, ...) failed: %d", bufferHandle, error);
+
+ return static_cast<status_t>(error);
}
-Error Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage,
- const IMapper::Rect& accessRegion,
- int acquireFence, YCbCrLayout* outLayout) const
-{
+status_t Gralloc2Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ IMapper::Rect accessRegion = sGralloc2Rect(bounds);
+
// put acquireFence in a hidl_handle
hardware::hidl_handle acquireFenceHandle;
NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
@@ -252,6 +280,7 @@
acquireFenceHandle = h;
}
+ YCbCrLayout layout;
Error error;
auto ret = mMapper->lockYCbCr(buffer, usage, accessRegion,
acquireFenceHandle,
@@ -262,19 +291,27 @@
return;
}
- *outLayout = tmpLayout;
+ layout = tmpLayout;
});
+ if (error == Error::NONE) {
+ ycbcr->y = layout.y;
+ ycbcr->cb = layout.cb;
+ ycbcr->cr = layout.cr;
+ ycbcr->ystride = static_cast<size_t>(layout.yStride);
+ ycbcr->cstride = static_cast<size_t>(layout.cStride);
+ ycbcr->chroma_step = static_cast<size_t>(layout.chromaStep);
+ }
+
// we own acquireFence even on errors
if (acquireFence >= 0) {
close(acquireFence);
}
- return (ret.isOk()) ? error : kTransactionError;
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
}
-int Mapper::unlock(buffer_handle_t bufferHandle) const
-{
+int Gralloc2Mapper::unlock(buffer_handle_t bufferHandle) const {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
int releaseFence = -1;
@@ -299,10 +336,7 @@
}
});
- if (!ret.isOk()) {
- error = kTransactionError;
- }
-
+ error = (ret.isOk()) ? error : kTransactionError;
if (error != Error::NONE) {
ALOGE("unlock(%p) failed with %d", buffer, error);
}
@@ -310,17 +344,19 @@
return releaseFence;
}
-Allocator::Allocator(const Mapper& mapper)
- : mMapper(mapper)
-{
+Gralloc2Allocator::Gralloc2Allocator(const Gralloc2Mapper& mapper) : mMapper(mapper) {
mAllocator = IAllocator::getService();
if (mAllocator == nullptr) {
- LOG_ALWAYS_FATAL("gralloc-alloc is missing");
+ ALOGW("allocator 2.x is not supported");
+ return;
}
}
-std::string Allocator::dumpDebugInfo() const
-{
+bool Gralloc2Allocator::isSupported() const {
+ return mAllocator != nullptr;
+}
+
+std::string Gralloc2Allocator::dumpDebugInfo() const {
std::string debugInfo;
mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) {
@@ -330,40 +366,51 @@
return debugInfo;
}
-Error Allocator::allocate(BufferDescriptor descriptor, uint32_t count,
- uint32_t* outStride, buffer_handle_t* outBufferHandles) const
-{
- Error error;
- auto ret = mAllocator->allocate(descriptor, count,
- [&](const auto& tmpError, const auto& tmpStride,
- const auto& tmpBuffers) {
- error = tmpError;
- if (tmpError != Error::NONE) {
- return;
- }
+status_t Gralloc2Allocator::allocate(uint32_t width, uint32_t height, PixelFormat format,
+ uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
+ uint32_t* outStride, buffer_handle_t* outBufferHandles) const {
+ IMapper::BufferDescriptorInfo descriptorInfo = {};
+ descriptorInfo.width = width;
+ descriptorInfo.height = height;
+ descriptorInfo.layerCount = layerCount;
+ descriptorInfo.format = static_cast<hardware::graphics::common::V1_1::PixelFormat>(format);
+ descriptorInfo.usage = usage;
- // import buffers
- for (uint32_t i = 0; i < count; i++) {
- error = mMapper.importBuffer(tmpBuffers[i],
- &outBufferHandles[i]);
- if (error != Error::NONE) {
- for (uint32_t j = 0; j < i; j++) {
- mMapper.freeBuffer(outBufferHandles[j]);
- outBufferHandles[j] = nullptr;
- }
- return;
- }
- }
+ BufferDescriptor descriptor;
+ status_t error = mMapper.createDescriptor(static_cast<void*>(&descriptorInfo),
+ static_cast<void*>(&descriptor));
+ if (error != NO_ERROR) {
+ return error;
+ }
- *outStride = tmpStride;
- });
+ auto ret = mAllocator->allocate(descriptor, bufferCount,
+ [&](const auto& tmpError, const auto& tmpStride,
+ const auto& tmpBuffers) {
+ error = static_cast<status_t>(tmpError);
+ if (tmpError != Error::NONE) {
+ return;
+ }
+
+ // import buffers
+ for (uint32_t i = 0; i < bufferCount; i++) {
+ error = mMapper.importBuffer(tmpBuffers[i],
+ &outBufferHandles[i]);
+ if (error != NO_ERROR) {
+ for (uint32_t j = 0; j < i; j++) {
+ mMapper.freeBuffer(outBufferHandles[j]);
+ outBufferHandles[j] = nullptr;
+ }
+ return;
+ }
+ }
+
+ *outStride = tmpStride;
+ });
// make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now
hardware::IPCThreadState::self()->flushCommands();
- return (ret.isOk()) ? error : kTransactionError;
+ return (ret.isOk()) ? error : static_cast<status_t>(kTransactionError);
}
-} // namespace Gralloc2
-
} // namespace android
diff --git a/libs/ui/Gralloc3.cpp b/libs/ui/Gralloc3.cpp
new file mode 100644
index 0000000..128200e
--- /dev/null
+++ b/libs/ui/Gralloc3.cpp
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2016 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 "Gralloc3"
+
+#include <hidl/ServiceManagement.h>
+#include <hwbinder/IPCThreadState.h>
+#include <ui/Gralloc3.h>
+
+#include <inttypes.h>
+#include <log/log.h>
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wzero-length-array"
+#include <sync/sync.h>
+#pragma clang diagnostic pop
+
+using android::hardware::graphics::allocator::V3_0::IAllocator;
+using android::hardware::graphics::common::V1_1::BufferUsage;
+using android::hardware::graphics::mapper::V3_0::BufferDescriptor;
+using android::hardware::graphics::mapper::V3_0::Error;
+using android::hardware::graphics::mapper::V3_0::IMapper;
+using android::hardware::graphics::mapper::V3_0::YCbCrLayout;
+
+namespace android {
+
+namespace {
+
+static constexpr Error kTransactionError = Error::NO_RESOURCES;
+
+uint64_t getValidUsageBits() {
+ static const uint64_t validUsageBits = []() -> uint64_t {
+ uint64_t bits = 0;
+ for (const auto bit :
+ hardware::hidl_enum_range<hardware::graphics::common::V1_0::BufferUsage>()) {
+ bits = bits | bit;
+ }
+ for (const auto bit :
+ hardware::hidl_enum_range<hardware::graphics::common::V1_1::BufferUsage>()) {
+ bits = bits | bit;
+ }
+ return bits;
+ }();
+ return validUsageBits;
+}
+
+static inline IMapper::Rect sGralloc3Rect(const Rect& rect) {
+ IMapper::Rect outRect{};
+ outRect.left = rect.left;
+ outRect.top = rect.top;
+ outRect.width = rect.width();
+ outRect.height = rect.height();
+ return outRect;
+}
+static inline void sBufferDescriptorInfo(uint32_t width, uint32_t height,
+ android::PixelFormat format, uint32_t layerCount,
+ uint64_t usage,
+ IMapper::BufferDescriptorInfo* outDescriptorInfo) {
+ outDescriptorInfo->width = width;
+ outDescriptorInfo->height = height;
+ outDescriptorInfo->layerCount = layerCount;
+ outDescriptorInfo->format = static_cast<hardware::graphics::common::V1_1::PixelFormat>(format);
+ outDescriptorInfo->usage = usage;
+}
+
+} // anonymous namespace
+
+void Gralloc3Mapper::preload() {
+ android::hardware::preloadPassthroughService<IMapper>();
+}
+
+Gralloc3Mapper::Gralloc3Mapper() {
+ mMapper = IMapper::getService();
+ if (mMapper == nullptr) {
+ ALOGW("mapper 3.x is not supported");
+ return;
+ }
+ if (mMapper->isRemote()) {
+ LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
+ }
+}
+
+bool Gralloc3Mapper::isSupported() const {
+ return mMapper != nullptr;
+}
+
+status_t Gralloc3Mapper::validateBufferDescriptorInfo(
+ IMapper::BufferDescriptorInfo* descriptorInfo) const {
+ uint64_t validUsageBits = getValidUsageBits();
+
+ if (descriptorInfo->usage & ~validUsageBits) {
+ ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64,
+ descriptorInfo->usage & ~validUsageBits);
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+}
+
+status_t Gralloc3Mapper::createDescriptor(void* bufferDescriptorInfo,
+ void* outBufferDescriptor) const {
+ IMapper::BufferDescriptorInfo* descriptorInfo =
+ static_cast<IMapper::BufferDescriptorInfo*>(bufferDescriptorInfo);
+ BufferDescriptor* outDescriptor = static_cast<BufferDescriptor*>(outBufferDescriptor);
+
+ status_t status = validateBufferDescriptorInfo(descriptorInfo);
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ Error error;
+ auto hidl_cb = [&](const auto& tmpError, const auto& tmpDescriptor) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outDescriptor = tmpDescriptor;
+ };
+
+ hardware::Return<void> ret = mMapper->createDescriptor(*descriptorInfo, hidl_cb);
+
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+status_t Gralloc3Mapper::importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const {
+ Error error;
+ auto ret = mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outBufferHandle = static_cast<buffer_handle_t>(tmpBuffer);
+ });
+
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+void Gralloc3Mapper::freeBuffer(buffer_handle_t bufferHandle) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ auto ret = mMapper->freeBuffer(buffer);
+
+ auto error = (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError;
+ ALOGE_IF(error != Error::NONE, "freeBuffer(%p) failed with %d", buffer, error);
+}
+
+status_t Gralloc3Mapper::validateBufferSize(buffer_handle_t bufferHandle, uint32_t width,
+ uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const {
+ IMapper::BufferDescriptorInfo descriptorInfo;
+ sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
+
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ auto ret = mMapper->validateBufferSize(buffer, descriptorInfo, stride);
+
+ return static_cast<status_t>((ret.isOk()) ? static_cast<Error>(ret) : kTransactionError);
+}
+
+void Gralloc3Mapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const {
+ *outNumFds = uint32_t(bufferHandle->numFds);
+ *outNumInts = uint32_t(bufferHandle->numInts);
+
+ Error error;
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ auto ret = mMapper->getTransportSize(buffer,
+ [&](const auto& tmpError, const auto& tmpNumFds,
+ const auto& tmpNumInts) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outNumFds = tmpNumFds;
+ *outNumInts = tmpNumInts;
+ });
+
+ error = (ret.isOk()) ? error : kTransactionError;
+
+ ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d", buffer, error);
+}
+
+status_t Gralloc3Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ IMapper::Rect accessRegion = sGralloc3Rect(bounds);
+
+ // put acquireFence in a hidl_handle
+ hardware::hidl_handle acquireFenceHandle;
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+ if (acquireFence >= 0) {
+ auto h = native_handle_init(acquireFenceStorage, 1, 0);
+ h->data[0] = acquireFence;
+ acquireFenceHandle = h;
+ }
+
+ Error error;
+ auto ret = mMapper->lock(buffer, usage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpData) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outData = tmpData;
+ });
+
+ // we own acquireFence even on errors
+ if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+
+ error = (ret.isOk()) ? error : kTransactionError;
+
+ ALOGW_IF(error != Error::NONE, "lock(%p, ...) failed: %d", bufferHandle, error);
+
+ return static_cast<status_t>(error);
+}
+
+status_t Gralloc3Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ IMapper::Rect accessRegion = sGralloc3Rect(bounds);
+
+ // put acquireFence in a hidl_handle
+ hardware::hidl_handle acquireFenceHandle;
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+ if (acquireFence >= 0) {
+ auto h = native_handle_init(acquireFenceStorage, 1, 0);
+ h->data[0] = acquireFence;
+ acquireFenceHandle = h;
+ }
+
+ YCbCrLayout layout;
+ Error error;
+ auto ret = mMapper->lockYCbCr(buffer, usage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpLayout) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ layout = tmpLayout;
+ });
+
+ if (error == Error::NONE) {
+ ycbcr->y = layout.y;
+ ycbcr->cb = layout.cb;
+ ycbcr->cr = layout.cr;
+ ycbcr->ystride = static_cast<size_t>(layout.yStride);
+ ycbcr->cstride = static_cast<size_t>(layout.cStride);
+ ycbcr->chroma_step = static_cast<size_t>(layout.chromaStep);
+ }
+
+ // we own acquireFence even on errors
+ if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+int Gralloc3Mapper::unlock(buffer_handle_t bufferHandle) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ int releaseFence = -1;
+ Error error;
+ auto ret = mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ auto fenceHandle = tmpReleaseFence.getNativeHandle();
+ if (fenceHandle && fenceHandle->numFds == 1) {
+ int fd = dup(fenceHandle->data[0]);
+ if (fd >= 0) {
+ releaseFence = fd;
+ } else {
+ ALOGD("failed to dup unlock release fence");
+ sync_wait(fenceHandle->data[0], -1);
+ }
+ }
+ });
+
+ if (!ret.isOk()) {
+ error = kTransactionError;
+ }
+
+ if (error != Error::NONE) {
+ ALOGE("unlock(%p) failed with %d", buffer, error);
+ }
+
+ return releaseFence;
+}
+
+Gralloc3Allocator::Gralloc3Allocator(const Gralloc3Mapper& mapper) : mMapper(mapper) {
+ mAllocator = IAllocator::getService();
+ if (mAllocator == nullptr) {
+ ALOGW("allocator 3.x is not supported");
+ return;
+ }
+}
+
+bool Gralloc3Allocator::isSupported() const {
+ return mAllocator != nullptr;
+}
+
+std::string Gralloc3Allocator::dumpDebugInfo() const {
+ std::string debugInfo;
+
+ mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
+
+ return debugInfo;
+}
+
+status_t Gralloc3Allocator::allocate(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
+ uint32_t* outStride, buffer_handle_t* outBufferHandles) const {
+ IMapper::BufferDescriptorInfo descriptorInfo;
+ sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
+
+ BufferDescriptor descriptor;
+ status_t error = mMapper.createDescriptor(static_cast<void*>(&descriptorInfo),
+ static_cast<void*>(&descriptor));
+ if (error != NO_ERROR) {
+ return error;
+ }
+
+ auto ret = mAllocator->allocate(descriptor, bufferCount,
+ [&](const auto& tmpError, const auto& tmpStride,
+ const auto& tmpBuffers) {
+ error = static_cast<status_t>(tmpError);
+ if (tmpError != Error::NONE) {
+ return;
+ }
+
+ // import buffers
+ for (uint32_t i = 0; i < bufferCount; i++) {
+ error = mMapper.importBuffer(tmpBuffers[i],
+ &outBufferHandles[i]);
+ if (error != NO_ERROR) {
+ for (uint32_t j = 0; j < i; j++) {
+ mMapper.freeBuffer(outBufferHandles[j]);
+ outBufferHandles[j] = nullptr;
+ }
+ return;
+ }
+ }
+ *outStride = tmpStride;
+ });
+
+ // make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now
+ hardware::IPCThreadState::self()->flushCommands();
+
+ return (ret.isOk()) ? error : static_cast<status_t>(kTransactionError);
+}
+
+} // namespace android
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index f56e6b9..efb5798 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -29,7 +29,9 @@
#include <utils/Singleton.h>
#include <utils/Trace.h>
+#include <ui/Gralloc.h>
#include <ui/Gralloc2.h>
+#include <ui/Gralloc3.h>
#include <ui/GraphicBufferMapper.h>
namespace android {
@@ -43,11 +45,17 @@
KeyedVector<buffer_handle_t,
GraphicBufferAllocator::alloc_rec_t> GraphicBufferAllocator::sAllocList;
-GraphicBufferAllocator::GraphicBufferAllocator()
- : mMapper(GraphicBufferMapper::getInstance()),
- mAllocator(std::make_unique<Gralloc2::Allocator>(
- mMapper.getGrallocMapper()))
-{
+GraphicBufferAllocator::GraphicBufferAllocator() : mMapper(GraphicBufferMapper::getInstance()) {
+ mAllocator = std::make_unique<const Gralloc3Allocator>(
+ reinterpret_cast<const Gralloc3Mapper&>(mMapper.getGrallocMapper()));
+ if (!mAllocator->isSupported()) {
+ mAllocator = std::make_unique<const Gralloc2Allocator>(
+ reinterpret_cast<const Gralloc2Mapper&>(mMapper.getGrallocMapper()));
+ }
+
+ if (!mAllocator->isSupported()) {
+ LOG_ALWAYS_FATAL("gralloc-allocator is missing");
+ }
}
GraphicBufferAllocator::~GraphicBufferAllocator() {}
@@ -104,15 +112,9 @@
// TODO(b/72323293, b/72703005): Remove these invalid bits from callers
usage &= ~static_cast<uint64_t>((1 << 10) | (1 << 13));
- Gralloc2::IMapper::BufferDescriptorInfo info = {};
- info.width = width;
- info.height = height;
- info.layerCount = layerCount;
- info.format = static_cast<Gralloc2::PixelFormat>(format);
- info.usage = usage;
-
- Gralloc2::Error error = mAllocator->allocate(info, stride, handle);
- if (error == Gralloc2::Error::NONE) {
+ status_t error =
+ mAllocator->allocate(width, height, format, layerCount, usage, 1, stride, handle);
+ if (error == NO_ERROR) {
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
uint32_t bpp = bytesPerPixel(format);
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 2d8e582..b049329 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -32,7 +32,9 @@
#include <utils/Log.h>
#include <utils/Trace.h>
+#include <ui/Gralloc.h>
#include <ui/Gralloc2.h>
+#include <ui/Gralloc3.h>
#include <ui/GraphicBuffer.h>
#include <system/graphics.h>
@@ -43,12 +45,19 @@
ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )
void GraphicBufferMapper::preloadHal() {
- Gralloc2::Mapper::preload();
+ Gralloc2Mapper::preload();
+ Gralloc3Mapper::preload();
}
-GraphicBufferMapper::GraphicBufferMapper()
- : mMapper(std::make_unique<const Gralloc2::Mapper>())
-{
+GraphicBufferMapper::GraphicBufferMapper() {
+ mMapper = std::make_unique<const Gralloc3Mapper>();
+ if (!mMapper->isSupported()) {
+ mMapper = std::make_unique<const Gralloc2Mapper>();
+ }
+
+ if (!mMapper->isSupported()) {
+ LOG_ALWAYS_FATAL("gralloc-mapper is missing");
+ }
}
status_t GraphicBufferMapper::importBuffer(buffer_handle_t rawHandle,
@@ -59,22 +68,15 @@
ATRACE_CALL();
buffer_handle_t bufferHandle;
- Gralloc2::Error error = mMapper->importBuffer(
- hardware::hidl_handle(rawHandle), &bufferHandle);
- if (error != Gralloc2::Error::NONE) {
+ status_t error = mMapper->importBuffer(hardware::hidl_handle(rawHandle), &bufferHandle);
+ if (error != NO_ERROR) {
ALOGW("importBuffer(%p) failed: %d", rawHandle, error);
- return static_cast<status_t>(error);
+ return error;
}
- Gralloc2::IMapper::BufferDescriptorInfo info = {};
- info.width = width;
- info.height = height;
- info.layerCount = layerCount;
- info.format = static_cast<Gralloc2::PixelFormat>(format);
- info.usage = usage;
-
- error = mMapper->validateBufferSize(bufferHandle, info, stride);
- if (error != Gralloc2::Error::NONE) {
+ error = mMapper->validateBufferSize(bufferHandle, width, height, format, layerCount, usage,
+ stride);
+ if (error != NO_ERROR) {
ALOGE("validateBufferSize(%p) failed: %d", rawHandle, error);
freeBuffer(bufferHandle);
return static_cast<status_t>(error);
@@ -100,15 +102,6 @@
return NO_ERROR;
}
-static inline Gralloc2::IMapper::Rect asGralloc2Rect(const Rect& rect) {
- Gralloc2::IMapper::Rect outRect{};
- outRect.left = rect.left;
- outRect.top = rect.top;
- outRect.width = rect.width();
- outRect.height = rect.height();
- return outRect;
-}
-
status_t GraphicBufferMapper::lock(buffer_handle_t handle, uint32_t usage,
const Rect& bounds, void** vaddr)
{
@@ -146,13 +139,7 @@
const uint64_t usage = static_cast<uint64_t>(
android_convertGralloc1To0Usage(producerUsage, consumerUsage));
- Gralloc2::Error error = mMapper->lock(handle, usage,
- asGralloc2Rect(bounds), fenceFd, vaddr);
-
- ALOGW_IF(error != Gralloc2::Error::NONE, "lock(%p, ...) failed: %d",
- handle, error);
-
- return static_cast<status_t>(error);
+ return mMapper->lock(handle, usage, bounds, fenceFd, vaddr);
}
status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle,
@@ -160,19 +147,7 @@
{
ATRACE_CALL();
- Gralloc2::YCbCrLayout layout;
- Gralloc2::Error error = mMapper->lock(handle, usage,
- asGralloc2Rect(bounds), fenceFd, &layout);
- if (error == Gralloc2::Error::NONE) {
- ycbcr->y = layout.y;
- ycbcr->cb = layout.cb;
- ycbcr->cr = layout.cr;
- ycbcr->ystride = static_cast<size_t>(layout.yStride);
- ycbcr->cstride = static_cast<size_t>(layout.cStride);
- ycbcr->chroma_step = static_cast<size_t>(layout.chromaStep);
- }
-
- return static_cast<status_t>(error);
+ return mMapper->lock(handle, usage, bounds, fenceFd, ycbcr);
}
status_t GraphicBufferMapper::unlockAsync(buffer_handle_t handle, int *fenceFd)
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/libs/ui/Size.cpp
similarity index 63%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to libs/ui/Size.cpp
index e6ac6bf..d2996d1 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/libs/ui/Size.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -14,14 +14,11 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <ui/Size.h>
-namespace android {
-namespace mock {
+namespace android::ui {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+const Size Size::INVALID{-1, -1};
+const Size Size::EMPTY{0, 0};
-} // namespace mock
-} // namespace android
+} // namespace android::ui
diff --git a/libs/ui/Transform.cpp b/libs/ui/Transform.cpp
index 25128ef..d13942d 100644
--- a/libs/ui/Transform.cpp
+++ b/libs/ui/Transform.cpp
@@ -16,6 +16,7 @@
#include <math.h>
+#include <android-base/stringprintf.h>
#include <cutils/compiler.h>
#include <ui/Region.h>
#include <ui/Transform.h>
@@ -380,44 +381,47 @@
return (getOrientation() & ROT_INVALID) ? false : true;
}
-void Transform::dump(const char* name) const
-{
- type(); // updates the type
+void Transform::dump(std::string& out, const char* name) const {
+ using android::base::StringAppendF;
- String8 flags, type;
- const mat33& m(mMatrix);
- uint32_t orient = mType >> 8;
+ type(); // Ensure the information in mType is up to date
- if (orient&ROT_INVALID) {
- flags.append("ROT_INVALID ");
+ const uint32_t type = mType;
+ const uint32_t orient = type >> 8;
+
+ StringAppendF(&out, "%s 0x%08x (", name, orient);
+
+ if (orient & ROT_INVALID) {
+ out.append("ROT_INVALID ");
} else {
- if (orient&ROT_90) {
- flags.append("ROT_90 ");
+ if (orient & ROT_90) {
+ out.append("ROT_90 ");
} else {
- flags.append("ROT_0 ");
+ out.append("ROT_0 ");
}
- if (orient&FLIP_V)
- flags.append("FLIP_V ");
- if (orient&FLIP_H)
- flags.append("FLIP_H ");
+ if (orient & FLIP_V) out.append("FLIP_V ");
+ if (orient & FLIP_H) out.append("FLIP_H ");
}
- if (!(mType&(SCALE|ROTATE|TRANSLATE)))
- type.append("IDENTITY ");
- if (mType&SCALE)
- type.append("SCALE ");
- if (mType&ROTATE)
- type.append("ROTATE ");
- if (mType&TRANSLATE)
- type.append("TRANSLATE ");
+ StringAppendF(&out, ") 0x%02x (", type);
- ALOGD("%s 0x%08x (%s, %s)", name, mType, flags.string(), type.string());
- ALOGD("%.4f %.4f %.4f", static_cast<double>(m[0][0]), static_cast<double>(m[1][0]),
- static_cast<double>(m[2][0]));
- ALOGD("%.4f %.4f %.4f", static_cast<double>(m[0][1]), static_cast<double>(m[1][1]),
- static_cast<double>(m[2][1]));
- ALOGD("%.4f %.4f %.4f", static_cast<double>(m[0][2]), static_cast<double>(m[1][2]),
- static_cast<double>(m[2][2]));
+ if (!(type & (SCALE | ROTATE | TRANSLATE))) out.append("IDENTITY ");
+ if (type & SCALE) out.append("SCALE ");
+ if (type & ROTATE) out.append("ROTATE ");
+ if (type & TRANSLATE) out.append("TRANSLATE ");
+
+ out.append(")\n");
+
+ for (size_t i = 0; i < 3; i++) {
+ StringAppendF(&out, " %.4f %.4f %.4f\n", static_cast<double>(mMatrix[0][i]),
+ static_cast<double>(mMatrix[1][i]), static_cast<double>(mMatrix[2][i]));
+ }
+}
+
+void Transform::dump(const char* name) const {
+ std::string out;
+ dump(out, name);
+ ALOGD("%s", out.c_str());
}
} // namespace ui
diff --git a/libs/ui/include/ui/Gralloc.h b/libs/ui/include/ui/Gralloc.h
new file mode 100644
index 0000000..92bf043
--- /dev/null
+++ b/libs/ui/include/ui/Gralloc.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016 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_UI_GRALLOC_H
+#define ANDROID_UI_GRALLOC_H
+
+#include <string>
+
+#include <hidl/HidlSupport.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+// A wrapper to IMapper
+class GrallocMapper {
+public:
+ virtual ~GrallocMapper();
+
+ virtual bool isSupported() const = 0;
+
+ virtual status_t createDescriptor(void* bufferDescriptorInfo,
+ void* outBufferDescriptor) const = 0;
+
+ // Import a buffer that is from another HAL, another process, or is
+ // cloned.
+ //
+ // The returned handle must be freed with freeBuffer.
+ virtual status_t importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const = 0;
+
+ virtual void freeBuffer(buffer_handle_t bufferHandle) const = 0;
+
+ virtual status_t validateBufferSize(buffer_handle_t bufferHandle, uint32_t width,
+ uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const = 0;
+
+ virtual void getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const = 0;
+
+ // The ownership of acquireFence is always transferred to the callee, even
+ // on errors.
+ virtual status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData) const = 0;
+
+ // The ownership of acquireFence is always transferred to the callee, even
+ // on errors.
+ virtual status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const = 0;
+
+ // unlock returns a fence sync object (or -1) and the fence sync object is
+ // owned by the caller
+ virtual int unlock(buffer_handle_t bufferHandle) const = 0;
+};
+
+// A wrapper to IAllocator
+class GrallocAllocator {
+public:
+ virtual ~GrallocAllocator();
+
+ virtual bool isSupported() const = 0;
+
+ virtual std::string dumpDebugInfo() const = 0;
+
+ /*
+ * The returned buffers are already imported and must not be imported
+ * again. outBufferHandles must point to a space that can contain at
+ * least "bufferCount" buffer_handle_t.
+ */
+ virtual status_t allocate(uint32_t width, uint32_t height, PixelFormat format,
+ uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
+ uint32_t* outStride, buffer_handle_t* outBufferHandles) const = 0;
+};
+
+} // namespace android
+
+#endif // ANDROID_UI_GRALLOC_H
diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
index 5a8dbda..e03cb43 100644
--- a/libs/ui/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -23,119 +23,71 @@
#include <android/hardware/graphics/common/1.1/types.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <ui/Gralloc.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
#include <utils/StrongPointer.h>
namespace android {
-namespace Gralloc2 {
-
-using hardware::graphics::allocator::V2_0::IAllocator;
-using hardware::graphics::common::V1_1::BufferUsage;
-using hardware::graphics::common::V1_1::PixelFormat;
-using hardware::graphics::mapper::V2_1::IMapper;
-using hardware::graphics::mapper::V2_0::BufferDescriptor;
-using hardware::graphics::mapper::V2_0::Error;
-using hardware::graphics::mapper::V2_0::YCbCrLayout;
-
-// A wrapper to IMapper
-class Mapper {
+class Gralloc2Mapper : public GrallocMapper {
public:
static void preload();
- Mapper();
+ Gralloc2Mapper();
- Error createDescriptor(
- const IMapper::BufferDescriptorInfo& descriptorInfo,
- BufferDescriptor* outDescriptor) const;
+ bool isSupported() const override;
- // Import a buffer that is from another HAL, another process, or is
- // cloned.
- //
- // The returned handle must be freed with freeBuffer.
- Error importBuffer(const hardware::hidl_handle& rawHandle,
- buffer_handle_t* outBufferHandle) const;
+ status_t createDescriptor(void* bufferDescriptorInfo, void* outBufferDescriptor) const override;
- void freeBuffer(buffer_handle_t bufferHandle) const;
+ status_t importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const override;
- Error validateBufferSize(buffer_handle_t bufferHandle,
- const IMapper::BufferDescriptorInfo& descriptorInfo,
- uint32_t stride) const;
+ void freeBuffer(buffer_handle_t bufferHandle) const override;
- void getTransportSize(buffer_handle_t bufferHandle,
- uint32_t* outNumFds, uint32_t* outNumInts) const;
+ status_t validateBufferSize(buffer_handle_t bufferHandle, uint32_t width, uint32_t height,
+ android::PixelFormat format, uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const override;
- // The ownership of acquireFence is always transferred to the callee, even
- // on errors.
- Error lock(buffer_handle_t bufferHandle, uint64_t usage,
- const IMapper::Rect& accessRegion,
- int acquireFence, void** outData) const;
+ void getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const override;
- // The ownership of acquireFence is always transferred to the callee, even
- // on errors.
- Error lock(buffer_handle_t bufferHandle, uint64_t usage,
- const IMapper::Rect& accessRegion,
- int acquireFence, YCbCrLayout* outLayout) const;
+ status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData) const override;
- // unlock returns a fence sync object (or -1) and the fence sync object is
- // owned by the caller
- int unlock(buffer_handle_t bufferHandle) const;
+ status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const override;
+
+ int unlock(buffer_handle_t bufferHandle) const override;
private:
// Determines whether the passed info is compatible with the mapper.
- Error validateBufferDescriptorInfo(
- const IMapper::BufferDescriptorInfo& descriptorInfo) const;
+ status_t validateBufferDescriptorInfo(
+ hardware::graphics::mapper::V2_1::IMapper::BufferDescriptorInfo* descriptorInfo) const;
sp<hardware::graphics::mapper::V2_0::IMapper> mMapper;
- sp<IMapper> mMapperV2_1;
+ sp<hardware::graphics::mapper::V2_1::IMapper> mMapperV2_1;
};
-// A wrapper to IAllocator
-class Allocator {
+class Gralloc2Allocator : public GrallocAllocator {
public:
// An allocator relies on a mapper, and that mapper must be alive at all
// time.
- Allocator(const Mapper& mapper);
+ Gralloc2Allocator(const Gralloc2Mapper& mapper);
- std::string dumpDebugInfo() const;
+ bool isSupported() const override;
- /*
- * The returned buffers are already imported and must not be imported
- * again. outBufferHandles must point to a space that can contain at
- * least "count" buffer_handle_t.
- */
- Error allocate(BufferDescriptor descriptor, uint32_t count,
- uint32_t* outStride, buffer_handle_t* outBufferHandles) const;
+ std::string dumpDebugInfo() const override;
- Error allocate(BufferDescriptor descriptor,
- uint32_t* outStride, buffer_handle_t* outBufferHandle) const
- {
- return allocate(descriptor, 1, outStride, outBufferHandle);
- }
-
- Error allocate(const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t count,
- uint32_t* outStride, buffer_handle_t* outBufferHandles) const
- {
- BufferDescriptor descriptor;
- Error error = mMapper.createDescriptor(descriptorInfo, &descriptor);
- if (error == Error::NONE) {
- error = allocate(descriptor, count, outStride, outBufferHandles);
- }
- return error;
- }
-
- Error allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
- uint32_t* outStride, buffer_handle_t* outBufferHandle) const
- {
- return allocate(descriptorInfo, 1, outStride, outBufferHandle);
- }
+ status_t allocate(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount,
+ uint64_t usage, uint32_t bufferCount, uint32_t* outStride,
+ buffer_handle_t* outBufferHandles) const override;
private:
- const Mapper& mMapper;
- sp<IAllocator> mAllocator;
+ const Gralloc2Mapper& mMapper;
+ sp<hardware::graphics::allocator::V2_0::IAllocator> mAllocator;
};
-} // namespace Gralloc2
-
} // namespace android
#endif // ANDROID_UI_GRALLOC2_H
diff --git a/libs/ui/include/ui/Gralloc3.h b/libs/ui/include/ui/Gralloc3.h
new file mode 100644
index 0000000..510ce4a
--- /dev/null
+++ b/libs/ui/include/ui/Gralloc3.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016 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_UI_GRALLOC3_H
+#define ANDROID_UI_GRALLOC3_H
+
+#include <string>
+
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/common/1.1/types.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <ui/Gralloc.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class Gralloc3Mapper : public GrallocMapper {
+public:
+ static void preload();
+
+ Gralloc3Mapper();
+
+ bool isSupported() const override;
+
+ status_t createDescriptor(void* bufferDescriptorInfo, void* outBufferDescriptor) const override;
+
+ status_t importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const override;
+
+ void freeBuffer(buffer_handle_t bufferHandle) const override;
+
+ status_t validateBufferSize(buffer_handle_t bufferHandle, uint32_t width, uint32_t height,
+ android::PixelFormat format, uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const override;
+
+ void getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const override;
+
+ status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData) const override;
+
+ status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const override;
+
+ int unlock(buffer_handle_t bufferHandle) const override;
+
+private:
+ // Determines whether the passed info is compatible with the mapper.
+ status_t validateBufferDescriptorInfo(
+ hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo* descriptorInfo) const;
+
+ sp<hardware::graphics::mapper::V3_0::IMapper> mMapper;
+};
+
+class Gralloc3Allocator : public GrallocAllocator {
+public:
+ // An allocator relies on a mapper, and that mapper must be alive at all
+ // time.
+ Gralloc3Allocator(const Gralloc3Mapper& mapper);
+
+ bool isSupported() const override;
+
+ std::string dumpDebugInfo() const override;
+
+ status_t allocate(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount,
+ uint64_t usage, uint32_t bufferCount, uint32_t* outStride,
+ buffer_handle_t* outBufferHandles) const override;
+
+private:
+ const Gralloc3Mapper& mMapper;
+ sp<hardware::graphics::allocator::V3_0::IAllocator> mAllocator;
+};
+
+} // namespace android
+
+#endif // ANDROID_UI_GRALLOC3_H
diff --git a/libs/ui/include/ui/GraphicBufferAllocator.h b/libs/ui/include/ui/GraphicBufferAllocator.h
index 7e2b230..3a547b6 100644
--- a/libs/ui/include/ui/GraphicBufferAllocator.h
+++ b/libs/ui/include/ui/GraphicBufferAllocator.h
@@ -34,10 +34,7 @@
namespace android {
-namespace Gralloc2 {
-class Allocator;
-}
-
+class GrallocAllocator;
class GraphicBufferMapper;
class GraphicBufferAllocator : public Singleton<GraphicBufferAllocator>
@@ -75,7 +72,7 @@
~GraphicBufferAllocator();
GraphicBufferMapper& mMapper;
- const std::unique_ptr<const Gralloc2::Allocator> mAllocator;
+ std::unique_ptr<const GrallocAllocator> mAllocator;
};
// ---------------------------------------------------------------------------
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 7cf003d..156bd7a 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -35,10 +35,7 @@
// ---------------------------------------------------------------------------
-namespace Gralloc2 {
-class Mapper;
-}
-
+class GrallocMapper;
class Rect;
class GraphicBufferMapper : public Singleton<GraphicBufferMapper>
@@ -80,9 +77,8 @@
status_t unlockAsync(buffer_handle_t handle, int *fenceFd);
- const Gralloc2::Mapper& getGrallocMapper() const
- {
- return *mMapper;
+ const GrallocMapper& getGrallocMapper() const {
+ return reinterpret_cast<const GrallocMapper&>(*mMapper);
}
private:
@@ -90,7 +86,7 @@
GraphicBufferMapper();
- const std::unique_ptr<const Gralloc2::Mapper> mMapper;
+ std::unique_ptr<const GrallocMapper> mMapper;
};
// ---------------------------------------------------------------------------
diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h
index e9da087..1768805 100644
--- a/libs/ui/include/ui/Rect.h
+++ b/libs/ui/include/ui/Rect.h
@@ -24,6 +24,7 @@
#include <ui/FloatRect.h>
#include <ui/Point.h>
+#include <ui/Size.h>
#include <android/rect.h>
@@ -78,6 +79,13 @@
bottom = static_cast<int32_t>(floatRect.bottom + 0.5f);
}
+ inline explicit Rect(const ui::Size& size) {
+ left = 0;
+ top = 0;
+ right = size.width;
+ bottom = size.height;
+ }
+
void makeInvalid();
inline void clear() {
@@ -106,6 +114,8 @@
return bottom - top;
}
+ ui::Size getSize() const { return ui::Size(getWidth(), getHeight()); }
+
__attribute__((no_sanitize("signed-integer-overflow")))
inline Rect getBounds() const {
return Rect(right - left, bottom - top);
diff --git a/libs/ui/include/ui/Size.h b/libs/ui/include/ui/Size.h
new file mode 100644
index 0000000..c39d8af
--- /dev/null
+++ b/libs/ui/include/ui/Size.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2019 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 <algorithm>
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+#include <utility>
+
+namespace android {
+namespace ui {
+
+// Forward declare a few things.
+struct Size;
+bool operator==(const Size& lhs, const Size& rhs);
+
+/**
+ * A simple value type representing a two-dimensional size
+ */
+struct Size {
+ int32_t width;
+ int32_t height;
+
+ // Special values
+ static const Size INVALID;
+ static const Size EMPTY;
+
+ // ------------------------------------------------------------------------
+ // Construction
+ // ------------------------------------------------------------------------
+
+ Size() : Size(INVALID) {}
+ template <typename T>
+ Size(T&& w, T&& h)
+ : width(Size::clamp<int32_t, T>(std::forward<T>(w))),
+ height(Size::clamp<int32_t, T>(std::forward<T>(h))) {}
+
+ // ------------------------------------------------------------------------
+ // Accessors
+ // ------------------------------------------------------------------------
+
+ int32_t getWidth() const { return width; }
+ int32_t getHeight() const { return height; }
+
+ template <typename T>
+ void setWidth(T&& v) {
+ width = Size::clamp<int32_t, T>(std::forward<T>(v));
+ }
+ template <typename T>
+ void setHeight(T&& v) {
+ height = Size::clamp<int32_t, T>(std::forward<T>(v));
+ }
+
+ // ------------------------------------------------------------------------
+ // Assignment
+ // ------------------------------------------------------------------------
+
+ void set(const Size& size) { *this = size; }
+ template <typename T>
+ void set(T&& w, T&& h) {
+ set(Size(std::forward<T>(w), std::forward<T>(h)));
+ }
+
+ // Sets the value to INVALID
+ void makeInvalid() { set(INVALID); }
+
+ // Sets the value to EMPTY
+ void clear() { set(EMPTY); }
+
+ // ------------------------------------------------------------------------
+ // Semantic checks
+ // ------------------------------------------------------------------------
+
+ // Valid means non-negative width and height
+ bool isValid() const { return width >= 0 && height >= 0; }
+
+ // Empty means zero width and height
+ bool isEmpty() const { return *this == EMPTY; }
+
+ // ------------------------------------------------------------------------
+ // Clamp Helpers
+ // ------------------------------------------------------------------------
+
+ // Note: We use only features available in C++11 here for compatibility with
+ // external targets which include this file directly or indirectly and which
+ // themselves use C++11.
+
+ // C++11 compatible replacement for std::remove_cv_reference_t [C++20]
+ template <typename T>
+ using remove_cv_reference_t =
+ typename std::remove_cv<typename std::remove_reference<T>::type>::type;
+
+ // Takes a value of type FromType, and ensures it can be represented as a value of type ToType,
+ // clamping the input value to the output range if necessary.
+ template <typename ToType, typename FromType>
+ static Size::remove_cv_reference_t<ToType> clamp(
+ typename std::enable_if<
+ std::numeric_limits<Size::remove_cv_reference_t<ToType>>::is_bounded &&
+ std::numeric_limits<Size::remove_cv_reference_t<FromType>>::is_bounded,
+ FromType&&>::type v) {
+ static constexpr auto toHighest = std::numeric_limits<remove_cv_reference_t<ToType>>::max();
+ static constexpr auto toLowest =
+ std::numeric_limits<remove_cv_reference_t<ToType>>::lowest();
+ static constexpr auto fromHighest =
+ std::numeric_limits<remove_cv_reference_t<FromType>>::max();
+ static constexpr auto fromLowest =
+ std::numeric_limits<remove_cv_reference_t<FromType>>::lowest();
+
+ // A clamp is needed if the range of FromType is not a subset of the range of ToType
+ static constexpr bool isClampNeeded = (toLowest > fromLowest) || (toHighest < fromHighest);
+
+ // If a clamp is not needed, the conversion is just a trivial cast.
+ if (!isClampNeeded) {
+ return static_cast<ToType>(v);
+ }
+
+ // Otherwise we leverage implicit conversion to safely compare values of
+ // different types, to ensure we return a value clamped to the range of
+ // ToType.
+ return v < toLowest ? toLowest : (v > toHighest ? toHighest : static_cast<ToType>(v));
+ }
+};
+
+// ------------------------------------------------------------------------
+// Comparisons
+// ------------------------------------------------------------------------
+
+inline bool operator==(const Size& lhs, const Size& rhs) {
+ return lhs.width == rhs.width && lhs.height == rhs.height;
+}
+
+inline bool operator!=(const Size& lhs, const Size& rhs) {
+ return !operator==(lhs, rhs);
+}
+
+inline bool operator<(const Size& lhs, const Size& rhs) {
+ // Orders by increasing width, then height.
+ if (lhs.width != rhs.width) return lhs.width < rhs.width;
+ return lhs.height < rhs.height;
+}
+
+} // namespace ui
+} // namespace android
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h
index 900a5c4..dcb26cf 100644
--- a/libs/ui/include/ui/Transform.h
+++ b/libs/ui/include/ui/Transform.h
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
+#include <string>
#include <hardware/hardware.h>
#include <math/vec2.h>
@@ -90,6 +91,7 @@
Transform inverse() const;
// for debugging
+ void dump(std::string& result, const char* name) const;
void dump(const char* name) const;
private:
diff --git a/libs/ui/include_vndk/ui/Size.h b/libs/ui/include_vndk/ui/Size.h
new file mode 120000
index 0000000..fd2b21b
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Size.h
@@ -0,0 +1 @@
+../../include/ui/Size.h
\ No newline at end of file
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 665469e..373fa4f 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -71,3 +71,10 @@
],
cflags: ["-Wall", "-Werror"],
}
+
+cc_test {
+ name: "Size_test",
+ shared_libs: ["libui"],
+ srcs: ["Size_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
+}
diff --git a/libs/ui/tests/Size_test.cpp b/libs/ui/tests/Size_test.cpp
new file mode 100644
index 0000000..69e1ac8
--- /dev/null
+++ b/libs/ui/tests/Size_test.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2019 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 "SizeTest"
+
+#include <cmath>
+#include <cstdlib>
+
+#include <ui/Size.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace ui {
+
+TEST(SizeTest, BasicConstructionAndEqualityComparison) {
+ Size s(123, 456);
+
+ EXPECT_EQ(123, s.width);
+ EXPECT_EQ(123, s.getWidth());
+
+ EXPECT_EQ(456, s.height);
+ EXPECT_EQ(456, s.getHeight());
+
+ EXPECT_EQ(Size(123, 456), s);
+ EXPECT_NE(Size(456, 123), s);
+}
+
+TEST(SizeTest, BasicLessThanComparison) {
+ EXPECT_TRUE(Size(0, 1) < Size(2, 3));
+ EXPECT_FALSE(Size(2, 3) < Size(0, 1));
+
+ EXPECT_TRUE(Size(0, 3) < Size(2, 1));
+ EXPECT_FALSE(Size(2, 1) < Size(0, 3));
+
+ EXPECT_TRUE(Size(0, 1) < Size(0, 3));
+ EXPECT_FALSE(Size(0, 3) < Size(0, 1));
+
+ EXPECT_FALSE(Size(1, 1) < Size(1, 1));
+}
+
+TEST(SizeTest, ValidAndEmpty) {
+ {
+ Size s;
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(-1, -1);
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(1, -1000);
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(-1000, 1);
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(-1000, -1000);
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ const auto& s = Size::INVALID;
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(123, 456);
+ s.makeInvalid();
+ EXPECT_FALSE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+
+ {
+ Size s(0, 0);
+ EXPECT_TRUE(s.isValid());
+ EXPECT_TRUE(s.isEmpty());
+ }
+
+ {
+ const auto& s = Size::EMPTY;
+ EXPECT_TRUE(s.isValid());
+ EXPECT_TRUE(s.isEmpty());
+ }
+
+ {
+ Size s(123, 456);
+ s.clear();
+ EXPECT_TRUE(s.isValid());
+ EXPECT_TRUE(s.isEmpty());
+ }
+
+ {
+ Size s(123, 456);
+ EXPECT_TRUE(s.isValid());
+ EXPECT_FALSE(s.isEmpty());
+ }
+}
+
+TEST(SizeTest, Set) {
+ {
+ Size s;
+ s.setWidth(0);
+ EXPECT_EQ(Size(0, -1), s);
+ }
+
+ {
+ Size s;
+ s.setHeight(0);
+ EXPECT_EQ(Size(-1, 0), s);
+ }
+
+ {
+ Size s;
+ s.set(123, 456);
+ EXPECT_EQ(Size(123, 456), s);
+ }
+}
+
+template <typename T, typename U>
+void ClampTest(T input, U expected) {
+ // The constructor, set(), setWidth() and setHeight() all allow arbitrary
+ // conversions from other numeric types, and implement clamping if necessary.
+
+ EXPECT_EQ(Size(expected, expected), Size(input, input));
+
+ {
+ Size s;
+ s.set(input, input);
+ EXPECT_EQ(Size(expected, expected), s);
+ }
+
+ {
+ Size s;
+ s.setWidth(input);
+ EXPECT_EQ(expected, s.width);
+ }
+
+ {
+ Size s;
+ s.setHeight(input);
+ EXPECT_EQ(expected, s.height);
+ }
+}
+
+TEST(SizeTest, Int8RangeIsNotClamped) {
+ ClampTest(std::numeric_limits<int8_t>::max(), std::numeric_limits<int8_t>::max());
+ ClampTest(int8_t(0), int8_t(0));
+ ClampTest(std::numeric_limits<int8_t>::lowest(), std::numeric_limits<int8_t>::lowest());
+}
+
+TEST(SizeTest, FloatRangeIsClamped) {
+ ClampTest(std::numeric_limits<float>::max(), std::numeric_limits<int32_t>::max());
+ ClampTest(float(0), int32_t(0));
+ ClampTest(std::numeric_limits<float>::lowest(), std::numeric_limits<int32_t>::lowest());
+}
+
+} // namespace ui
+} // namespace android
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index b37d543..01c60d8 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -25,6 +25,7 @@
"android.hardware.configstore@1.1",
"android.hardware.configstore@1.2",
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
@@ -78,6 +79,7 @@
],
export_shared_lib_headers: [
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
@@ -115,6 +117,7 @@
"BufferLayerConsumer.cpp",
"BufferQueueLayer.cpp",
"BufferStateLayer.cpp",
+ "BufferStateLayerCache.cpp",
"Client.cpp",
"ColorLayer.cpp",
"ContainerLayer.cpp",
@@ -187,6 +190,7 @@
"android.hardware.configstore@1.0",
"android.hardware.configstore@1.2",
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
"libbinder",
"libcutils",
"libdisplayservicehidl",
diff --git a/services/surfaceflinger/BufferStateLayerCache.cpp b/services/surfaceflinger/BufferStateLayerCache.cpp
new file mode 100644
index 0000000..c82ad7b
--- /dev/null
+++ b/services/surfaceflinger/BufferStateLayerCache.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2019 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_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "BufferStateLayerCache"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "BufferStateLayerCache.h"
+
+#define MAX_CACHE_SIZE 64
+
+namespace android {
+
+int32_t BufferStateLayerCache::add(const sp<IBinder>& processToken,
+ const sp<GraphicBuffer>& buffer) {
+ std::lock_guard lock(mMutex);
+
+ auto& processCache = getProccessCache(processToken);
+
+ int32_t slot = findSlot(processCache);
+ if (slot < 0) {
+ return slot;
+ }
+
+ processCache[slot] = buffer;
+
+ return slot;
+}
+
+void BufferStateLayerCache::release(const sp<IBinder>& processToken, int32_t id) {
+ if (id < 0) {
+ ALOGE("invalid buffer id");
+ return;
+ }
+
+ std::lock_guard lock(mMutex);
+ auto& processCache = getProccessCache(processToken);
+
+ if (id >= processCache.size()) {
+ ALOGE("invalid buffer id");
+ return;
+ }
+ processCache[id] = nullptr;
+}
+
+sp<GraphicBuffer> BufferStateLayerCache::get(const sp<IBinder>& processToken, int32_t id) {
+ if (id < 0) {
+ ALOGE("invalid buffer id");
+ return nullptr;
+ }
+
+ std::lock_guard lock(mMutex);
+ auto& processCache = getProccessCache(processToken);
+
+ if (id >= processCache.size()) {
+ ALOGE("invalid buffer id");
+ return nullptr;
+ }
+ return processCache[id];
+}
+
+std::vector<sp<GraphicBuffer>>& BufferStateLayerCache::getProccessCache(
+ const sp<IBinder>& processToken) {
+ return mBuffers[processToken];
+}
+
+int32_t BufferStateLayerCache::findSlot(std::vector<sp<GraphicBuffer>>& processCache) {
+ int32_t slot = 0;
+
+ for (const sp<GraphicBuffer> buffer : processCache) {
+ if (!buffer) {
+ return slot;
+ }
+ slot++;
+ }
+
+ if (processCache.size() < MAX_CACHE_SIZE) {
+ processCache.push_back(nullptr);
+ return slot;
+ }
+
+ return -1;
+}
+
+}; // namespace android
diff --git a/services/surfaceflinger/BufferStateLayerCache.h b/services/surfaceflinger/BufferStateLayerCache.h
new file mode 100644
index 0000000..623f0c6
--- /dev/null
+++ b/services/surfaceflinger/BufferStateLayerCache.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 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 <android-base/thread_annotations.h>
+#include <binder/IBinder.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/RefBase.h>
+
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+
+class BufferStateLayerCache {
+public:
+ int32_t add(const sp<IBinder>& processToken, const sp<GraphicBuffer>& buffer);
+ void release(const sp<IBinder>& processToken, int32_t id);
+
+ sp<GraphicBuffer> get(const sp<IBinder>& processToken, int32_t id);
+
+private:
+ std::mutex mMutex;
+
+ std::vector<sp<GraphicBuffer>>& getProccessCache(const sp<IBinder>& processToken)
+ REQUIRES(mMutex);
+
+ int32_t findSlot(std::vector<sp<GraphicBuffer>>& proccessCache) REQUIRES(mMutex);
+
+ struct IBinderHash {
+ std::size_t operator()(const sp<IBinder>& strongPointer) const {
+ return std::hash<IBinder*>{}(strongPointer.get());
+ }
+ };
+
+ std::unordered_map<sp<IBinder> /*caching process*/, std::vector<sp<GraphicBuffer>>, IBinderHash>
+ mBuffers GUARDED_BY(mMutex);
+};
+
+}; // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index ec5e131..49fa84a 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -16,6 +16,8 @@
"libgui",
"liblayers_proto",
"liblog",
+ "libnativewindow",
+ "libsync",
"libtimestats_proto",
"libui",
"libutils",
@@ -35,6 +37,13 @@
defaults: ["libcompositionengine_defaults"],
srcs: [
"src/CompositionEngine.cpp",
+ "src/Display.cpp",
+ "src/DisplayColorProfile.cpp",
+ "src/DisplaySurface.cpp",
+ "src/DumpHelpers.cpp",
+ "src/Output.cpp",
+ "src/OutputCompositionState.cpp",
+ "src/RenderSurface.cpp",
],
local_include_dirs: ["include"],
export_include_dirs: ["include"],
@@ -45,6 +54,11 @@
defaults: ["libcompositionengine_defaults"],
srcs: [
"mock/CompositionEngine.cpp",
+ "mock/Display.cpp",
+ "mock/DisplayColorProfile.cpp",
+ "mock/DisplaySurface.cpp",
+ "mock/Output.cpp",
+ "mock/RenderSurface.cpp",
],
static_libs: [
"libgtest",
@@ -61,7 +75,11 @@
defaults: ["libcompositionengine_defaults"],
srcs: [
"tests/CompositionEngineTest.cpp",
+ "tests/DisplayColorProfileTest.cpp",
+ "tests/DisplayTest.cpp",
"tests/MockHWComposer.cpp",
+ "tests/OutputTest.cpp",
+ "tests/RenderSurfaceTest.cpp",
],
static_libs: [
"libcompositionengine",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
index af8515f..30cdb49 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
@@ -28,6 +28,10 @@
namespace compositionengine {
+class Display;
+
+struct DisplayCreationArgs;
+
/**
* Encapsulates all the interfaces and implementation details for performing
* display output composition.
@@ -36,6 +40,9 @@
public:
virtual ~CompositionEngine();
+ // Create a composition Display
+ virtual std::shared_ptr<Display> createDisplay(DisplayCreationArgs&&) = 0;
+
virtual HWComposer& getHwComposer() const = 0;
virtual void setHwComposer(std::unique_ptr<HWComposer>) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
new file mode 100644
index 0000000..dbcd3bd
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <optional>
+
+#include "DisplayHardware/DisplayIdentification.h"
+
+#include <compositionengine/Output.h>
+
+namespace android::compositionengine {
+
+struct RenderSurfaceCreationArgs;
+struct DisplayColorProfileCreationArgs;
+
+/**
+ * A display is a composition target which may be backed by a hardware composer
+ * display device
+ */
+class Display : public virtual Output {
+public:
+ // Gets the HWC DisplayId for the display if there is one
+ virtual const std::optional<DisplayId>& getId() const = 0;
+
+ // True if the display is secure
+ virtual bool isSecure() const = 0;
+
+ // True if the display is virtual
+ virtual bool isVirtual() const = 0;
+
+ // Releases the use of the HWC display, if any
+ virtual void disconnect() = 0;
+
+ // Creates a render color mode for the display
+ virtual void createDisplayColorProfile(DisplayColorProfileCreationArgs&&) = 0;
+
+ // Creates a render surface for the display
+ virtual void createRenderSurface(RenderSurfaceCreationArgs&&) = 0;
+
+protected:
+ ~Display() = default;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
new file mode 100644
index 0000000..e2a0d42
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2019 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 <cstdint>
+
+#include <ui/GraphicTypes.h>
+
+namespace android {
+
+class HdrCapabilities;
+
+namespace compositionengine {
+
+/**
+ * Encapsulates all the state and functionality for how colors should be
+ * transformed for a display
+ */
+class DisplayColorProfile {
+public:
+ constexpr static float sDefaultMinLumiance = 0.0;
+ constexpr static float sDefaultMaxLumiance = 500.0;
+
+ virtual ~DisplayColorProfile();
+
+ // Returns true if the profile is valid. This is meant to be checked post-
+ // construction and prior to use, as not everything is set up by the
+ // constructor.
+ virtual bool isValid() const = 0;
+
+ // Returns true if the profile supports the indicated render intent
+ virtual bool hasRenderIntent(ui::RenderIntent) const = 0;
+
+ // Returns true if the profile supports the indicated dataspace
+ virtual bool hasLegacyHdrSupport(ui::Dataspace) const = 0;
+
+ // Obtains the best combination of color mode and render intent for the
+ // input values
+ virtual void getBestColorMode(ui::Dataspace dataspace, ui::RenderIntent intent,
+ ui::Dataspace* outDataspace, ui::ColorMode* outMode,
+ ui::RenderIntent* outIntent) const = 0;
+
+ // Returns true if the profile supports a wide color gamut
+ virtual bool hasWideColorGamut() const = 0;
+
+ // Returns the per-frame metadata value for this profile
+ virtual int32_t getSupportedPerFrameMetadata() const = 0;
+
+ // Returns true if HWC for this profile supports HDR10Plus
+ virtual bool hasHDR10PlusSupport() const = 0;
+
+ // Returns true if HWC for this profile supports HDR10
+ virtual bool hasHDR10Support() const = 0;
+
+ // Returns true if HWC for this profile supports HLG
+ virtual bool hasHLGSupport() const = 0;
+
+ // Returns true if HWC for this profile supports DolbyVision
+ virtual bool hasDolbyVisionSupport() const = 0;
+
+ // Gets the supported HDR capabilities for the profile
+ virtual const HdrCapabilities& getHdrCapabilities() const = 0;
+
+ // Debugging
+ virtual void dump(std::string&) const = 0;
+};
+
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h
new file mode 100644
index 0000000..ef0f925
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <unordered_map>
+#include <vector>
+
+#include <ui/GraphicTypes.h>
+#include <ui/HdrCapabilities.h>
+
+namespace android::compositionengine {
+
+/**
+ * A parameter object for creating DisplayColorProfile instances
+ */
+struct DisplayColorProfileCreationArgs {
+ using HwcColorModes = std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>;
+
+ // True if this display supports a wide color gamut
+ bool hasWideColorGamut;
+
+ // The HDR capabilities supported by the HWC
+ HdrCapabilities hdrCapabilities;
+
+ // The per-frame metadata supported by the HWC
+ int32_t supportedPerFrameMetadata;
+
+ // The mapping of color modes and render intents supported by the HWC
+ HwcColorModes hwcColorModes;
+};
+
+/**
+ * A helper for setting up a DisplayColorProfileCreationArgs value in-line.
+ *
+ * Prefer this builder over raw structure initialization.
+ *
+ * Instead of:
+ *
+ * DisplayColorProfileCreationArgs{false, HdrCapabilities(), 0,
+ * HwcColorModes()}
+ *
+ * Prefer:
+ *
+ * DisplayColorProfileCreationArgsBuilder().setHasWideColorGamut(false)
+ * .setIsVirtual(false).setDisplayId(displayId).Build();
+ */
+class DisplayColorProfileCreationArgsBuilder {
+public:
+ DisplayColorProfileCreationArgs Build() { return std::move(mArgs); }
+
+ DisplayColorProfileCreationArgsBuilder& setHasWideColorGamut(bool hasWideColorGamut) {
+ mArgs.hasWideColorGamut = hasWideColorGamut;
+ return *this;
+ }
+ DisplayColorProfileCreationArgsBuilder& setHdrCapabilities(HdrCapabilities&& hdrCapabilities) {
+ mArgs.hdrCapabilities = std::move(hdrCapabilities);
+ return *this;
+ }
+ DisplayColorProfileCreationArgsBuilder& setSupportedPerFrameMetadata(
+ int32_t supportedPerFrameMetadata) {
+ mArgs.supportedPerFrameMetadata = supportedPerFrameMetadata;
+ return *this;
+ }
+ DisplayColorProfileCreationArgsBuilder& setHwcColorModes(
+ DisplayColorProfileCreationArgs::HwcColorModes&& hwcColorModes) {
+ mArgs.hwcColorModes = std::move(hwcColorModes);
+ return *this;
+ }
+
+private:
+ DisplayColorProfileCreationArgs mArgs;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
new file mode 100644
index 0000000..0b6b4e4
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <optional>
+
+#include "DisplayHardware/DisplayIdentification.h"
+
+namespace android::compositionengine {
+
+class CompositionEngine;
+
+/**
+ * A parameter object for creating Display instances
+ */
+struct DisplayCreationArgs {
+ // True if this display is secure
+ bool isSecure = false;
+
+ // True if this display is a virtual display
+ bool isVirtual = false;
+
+ // Identifies the display to the HWC, if composition is supported by it
+ std::optional<DisplayId> displayId;
+};
+
+/**
+ * A helper for setting up a DisplayCreationArgs value in-line.
+ * Prefer this builder over raw structure initialization.
+ *
+ * Instead of:
+ *
+ * DisplayCreationArgs{false, false, displayId}
+ *
+ * Prefer:
+ *
+ * DisplayCreationArgsBuilder().setIsSecure(false).setIsVirtual(false)
+ * .setDisplayId(displayId).build();
+ */
+class DisplayCreationArgsBuilder {
+public:
+ DisplayCreationArgs build() { return std::move(mArgs); }
+
+ DisplayCreationArgsBuilder& setIsSecure(bool isSecure) {
+ mArgs.isSecure = isSecure;
+ return *this;
+ }
+ DisplayCreationArgsBuilder& setIsVirtual(bool isVirtual) {
+ mArgs.isVirtual = isVirtual;
+ return *this;
+ }
+ DisplayCreationArgsBuilder& setDisplayId(std::optional<DisplayId> displayId) {
+ mArgs.displayId = displayId;
+ return *this;
+ }
+
+private:
+ DisplayCreationArgs mArgs;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
similarity index 80%
rename from services/surfaceflinger/DisplayHardware/DisplaySurface.h
rename to services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
index f744f5c..0e67acf 100644
--- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
@@ -14,23 +14,27 @@
* limitations under the License.
*/
-#ifndef ANDROID_SF_DISPLAY_SURFACE_H
-#define ANDROID_SF_DISPLAY_SURFACE_H
+#pragma once
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/StrongPointer.h>
-// ---------------------------------------------------------------------------
namespace android {
-// ---------------------------------------------------------------------------
class Fence;
class IGraphicBufferProducer;
class String8;
+namespace compositionengine {
+
+/**
+ * An abstraction for working with a display surface (buffer queue)
+ */
class DisplaySurface : public virtual RefBase {
public:
+ virtual ~DisplaySurface();
+
// beginFrame is called at the beginning of the composition loop, before
// the configuration is known. The DisplaySurface should do anything it
// needs to do to enable HWComposer to decide how to compose the frame.
@@ -44,9 +48,9 @@
// GLES and HWC for this frame.
enum CompositionType {
COMPOSITION_UNKNOWN = 0,
- COMPOSITION_GLES = 1,
- COMPOSITION_HWC = 2,
- COMPOSITION_MIXED = COMPOSITION_GLES | COMPOSITION_HWC
+ COMPOSITION_GLES = 1,
+ COMPOSITION_HWC = 2,
+ COMPOSITION_MIXED = COMPOSITION_GLES | COMPOSITION_HWC
};
virtual status_t prepareFrame(CompositionType compositionType) = 0;
@@ -70,15 +74,7 @@
virtual void resizeBuffers(const uint32_t w, const uint32_t h) = 0;
virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
-
-protected:
- DisplaySurface() {}
- virtual ~DisplaySurface() {}
};
-// ---------------------------------------------------------------------------
+} // namespace compositionengine
} // namespace android
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_SF_DISPLAY_SURFACE_H
-
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
new file mode 100644
index 0000000..2d00f0c
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <string>
+
+#include <math/mat4.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+
+namespace android::compositionengine {
+
+class DisplayColorProfile;
+class RenderSurface;
+
+namespace impl {
+struct OutputCompositionState;
+} // namespace impl
+
+/**
+ * Encapsulates all the state involved with composing layers for an output
+ */
+class Output {
+public:
+ // Returns true if the output is valid. This is meant to be checked post-
+ // construction and prior to use, as not everything is set up by the
+ // constructor.
+ virtual bool isValid() const = 0;
+
+ // Enables (or disables) composition on this output
+ virtual void setCompositionEnabled(bool) = 0;
+
+ // Sets the projection state to use
+ virtual void setProjection(const ui::Transform&, int32_t orientation, const Rect& frame,
+ const Rect& viewport, const Rect& scissor, bool needsFiltering) = 0;
+ // Sets the bounds to use
+ virtual void setBounds(const ui::Size&) = 0;
+
+ // Sets the layer stack filter for this output. If singleLayerStack is true,
+ // this output displays just the single layer stack specified by
+ // singleLayerStackId. Otherwise all layer stacks will be visible on this
+ // output.
+ virtual void setLayerStackFilter(bool singleLayerStack, uint32_t singleLayerStackId) = 0;
+
+ // Sets the color transform matrix to use
+ virtual void setColorTransform(const mat4&) = 0;
+
+ // Sets the output color mode
+ virtual void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) = 0;
+
+ // Outputs a string with a state dump
+ virtual void dump(std::string&) const = 0;
+
+ // Gets the debug name for the output
+ virtual const std::string& getName() const = 0;
+
+ // Sets a debug name for the output
+ virtual void setName(const std::string&) = 0;
+
+ // Gets the current render color mode for the output
+ virtual DisplayColorProfile* getDisplayColorProfile() const = 0;
+
+ // Gets the current render surface for the output
+ virtual RenderSurface* getRenderSurface() const = 0;
+
+ using OutputCompositionState = compositionengine::impl::OutputCompositionState;
+
+ // Gets the raw composition state data for the output
+ // TODO(lpique): Make this protected once it is only internally called.
+ virtual const OutputCompositionState& getState() const = 0;
+
+ // Allows mutable access to the raw composition state data for the output.
+ // This is meant to be used by the various functions that are part of the
+ // composition process.
+ // TODO(lpique): Make this protected once it is only internally called.
+ virtual OutputCompositionState& editState() = 0;
+
+ // Gets the physical space dirty region. If repaintEverything is true, this
+ // will be the full display bounds. Internally the dirty region is stored in
+ // logical (aka layer stack) space.
+ virtual Region getPhysicalSpaceDirtyRegion(bool repaintEverything) const = 0;
+
+ // Tests whether a given layerStackId belongs in this output
+ virtual bool belongsInOutput(uint32_t layerStackId) const = 0;
+
+protected:
+ ~Output() = default;
+
+ virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
+ virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
new file mode 100644
index 0000000..dd01b05
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <vector>
+
+#include <ui/Fence.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Size.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class GraphicBuffer;
+
+struct CompositionInfo;
+
+namespace compositionengine {
+
+/**
+ * Encapsulates everything for composing to a render surface with RenderEngine
+ */
+class RenderSurface {
+public:
+ virtual ~RenderSurface();
+
+ // Returns true if the render surface is valid. This is meant to be checked
+ // post-construction and prior to use, as not everything is set up by the
+ // constructor.
+ virtual bool isValid() const = 0;
+
+ // Performs one-time initialization of the render surface. This is meant
+ // to be called after the validation check.
+ virtual void initialize() = 0;
+
+ // Returns the bounds of the surface
+ virtual const ui::Size& getSize() const = 0;
+
+ // Gets the latest fence to pass to the HWC to signal that the surface
+ // buffer is done rendering
+ virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
+
+ // Sets the size of the surface
+ virtual void setDisplaySize(const ui::Size&) = 0;
+
+ // Sets the dataspace used for rendering the surface
+ virtual void setBufferDataspace(ui::Dataspace) = 0;
+
+ // Configures the protected rendering on the surface
+ virtual void setProtected(bool useProtected) = 0;
+
+ // Called to signal that rendering has started. 'mustRecompose' should be
+ // true if the entire frame must be recomposed.
+ virtual status_t beginFrame(bool mustRecompose) = 0;
+
+ // Prepares the frame for rendering
+ virtual status_t prepareFrame(std::vector<CompositionInfo>& compositionData) = 0;
+
+ // Allocates a buffer as scratch space for GPU composition
+ virtual sp<GraphicBuffer> dequeueBuffer() = 0;
+
+ // Queues the drawn buffer for consumption by HWC
+ virtual void queueBuffer() = 0;
+
+ // Called after the HWC calls are made to present the display
+ virtual void onPresentDisplayCompleted() = 0;
+
+ // Marks the current buffer has finished, so that it can be presented and
+ // swapped out
+ virtual void finishBuffer() = 0;
+
+ // Called to set the viewport and projection state for rendering into this
+ // surface
+ virtual void setViewportAndProjection() = 0;
+
+ // Called after the surface has been rendering to signal the surface should
+ // be made ready for displaying
+ virtual void flip() = 0;
+
+ // Debugging - Dumps the state of the RenderSurface to a string
+ virtual void dump(std::string& result) const = 0;
+
+ // Debugging - gets the page flip count for the RenderSurface
+ virtual std::uint32_t getPageFlipCount() const = 0;
+};
+
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h
new file mode 100644
index 0000000..a1230b3
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <memory>
+
+#include <compositionengine/DisplaySurface.h>
+#include <utils/StrongPointer.h>
+
+struct ANativeWindow;
+
+namespace android {
+
+namespace compositionengine {
+
+class Display;
+
+/**
+ * A parameter object for creating RenderSurface instances
+ */
+struct RenderSurfaceCreationArgs {
+ // The initial width of the surface
+ int32_t displayWidth;
+
+ // The initial height of the surface
+ int32_t displayHeight;
+
+ // The ANativeWindow for the buffer queue for this surface
+ sp<ANativeWindow> nativeWindow;
+
+ // The DisplaySurface for this surface
+ sp<DisplaySurface> displaySurface;
+};
+
+/**
+ * A helper for setting up a RenderSurfaceCreationArgs value in-line.
+ * Prefer this builder over raw structure initialization.
+ *
+ * Instead of:
+ *
+ * RenderSurfaceCreationArgs{1000, 1000, nativeWindow, displaySurface}
+ *
+ * Prefer:
+ *
+ * RenderSurfaceCreationArgsBuilder().setDisplayWidth(1000).setDisplayHeight(1000)
+ * .setNativeWindow(nativeWindow).setDisplaySurface(displaySurface).Build();
+ */
+class RenderSurfaceCreationArgsBuilder {
+public:
+ RenderSurfaceCreationArgs build() { return std::move(mArgs); }
+
+ RenderSurfaceCreationArgsBuilder& setDisplayWidth(int32_t displayWidth) {
+ mArgs.displayWidth = displayWidth;
+ return *this;
+ }
+ RenderSurfaceCreationArgsBuilder& setDisplayHeight(int32_t displayHeight) {
+ mArgs.displayHeight = displayHeight;
+ return *this;
+ }
+ RenderSurfaceCreationArgsBuilder& setNativeWindow(sp<ANativeWindow> nativeWindow) {
+ mArgs.nativeWindow = nativeWindow;
+ return *this;
+ }
+ RenderSurfaceCreationArgsBuilder& setDisplaySurface(sp<DisplaySurface> displaySurface) {
+ mArgs.displaySurface = displaySurface;
+ return *this;
+ }
+
+private:
+ RenderSurfaceCreationArgs mArgs;
+};
+
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
index 86d1774..e23c431 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
@@ -25,6 +25,9 @@
CompositionEngine();
~CompositionEngine() override;
+ std::shared_ptr<compositionengine::Display> createDisplay(
+ compositionengine::DisplayCreationArgs&&) override;
+
HWComposer& getHwComposer() const override;
void setHwComposer(std::unique_ptr<HWComposer>) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
new file mode 100644
index 0000000..0e20c43
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 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 <memory>
+
+#include <compositionengine/Display.h>
+#include <compositionengine/impl/Output.h>
+
+#include "DisplayHardware/DisplayIdentification.h"
+
+namespace android::compositionengine {
+
+class CompositionEngine;
+
+struct DisplayCreationArgs;
+
+namespace impl {
+
+class Display : public compositionengine::impl::Output, public compositionengine::Display {
+public:
+ Display(const CompositionEngine&, compositionengine::DisplayCreationArgs&&);
+ virtual ~Display();
+
+ // compositionengine::Output overrides
+ void dump(std::string&) const override;
+ void setColorTransform(const mat4&) override;
+ void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) override;
+
+ // compositionengine::Display overrides
+ const std::optional<DisplayId>& getId() const override;
+ bool isSecure() const override;
+ bool isVirtual() const override;
+ void disconnect() override;
+ void createDisplayColorProfile(compositionengine::DisplayColorProfileCreationArgs&&) override;
+ void createRenderSurface(compositionengine::RenderSurfaceCreationArgs&&) override;
+
+private:
+ const bool mIsVirtual;
+ std::optional<DisplayId> mId;
+};
+
+std::shared_ptr<compositionengine::Display> createDisplay(
+ const compositionengine::CompositionEngine&, compositionengine::DisplayCreationArgs&&);
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
new file mode 100644
index 0000000..49c2d2c
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <unordered_map>
+#include <vector>
+
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <ui/HdrCapabilities.h>
+
+namespace android::compositionengine {
+
+class CompositionEngine;
+class Display;
+
+namespace impl {
+
+class DisplayColorProfile : public compositionengine::DisplayColorProfile {
+public:
+ DisplayColorProfile(DisplayColorProfileCreationArgs&&);
+ ~DisplayColorProfile() override;
+
+ bool isValid() const override;
+
+ bool hasRenderIntent(ui::RenderIntent intent) const override;
+ bool hasLegacyHdrSupport(ui::Dataspace dataspace) const override;
+ void getBestColorMode(ui::Dataspace dataspace, ui::RenderIntent intent,
+ ui::Dataspace* outDataspace, ui::ColorMode* outMode,
+ ui::RenderIntent* outIntent) const override;
+
+ bool hasWideColorGamut() const override;
+ int32_t getSupportedPerFrameMetadata() const override;
+
+ // Whether h/w composer has native support for specific HDR type.
+ bool hasHDR10PlusSupport() const override;
+ bool hasHDR10Support() const override;
+ bool hasHLGSupport() const override;
+ bool hasDolbyVisionSupport() const override;
+
+ const HdrCapabilities& getHdrCapabilities() const override;
+
+ void dump(std::string&) const override;
+
+private:
+ void populateColorModes(const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes);
+ void addColorMode(const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes,
+ const ui::ColorMode mode, const ui::RenderIntent intent);
+
+ // Mappings from desired Dataspace/RenderIntent to the supported
+ // Dataspace/ColorMode/RenderIntent.
+ using ColorModeKey = uint64_t;
+ struct ColorModeValue {
+ ui::Dataspace dataspace;
+ ui::ColorMode colorMode;
+ ui::RenderIntent renderIntent;
+ };
+
+ static ColorModeKey getColorModeKey(ui::Dataspace dataspace, ui::RenderIntent intent) {
+ return (static_cast<uint64_t>(dataspace) << 32) | static_cast<uint32_t>(intent);
+ }
+
+ // Need to know if display is wide-color capable or not.
+ // Initialized by SurfaceFlinger when the DisplayDevice is created.
+ // Fed to RenderEngine during composition.
+ bool mHasWideColorGamut{false};
+ int32_t mSupportedPerFrameMetadata{0};
+ bool mHasHdr10Plus{false};
+ bool mHasHdr10{false};
+ bool mHasHLG{false};
+ bool mHasDolbyVision{false};
+ HdrCapabilities mHdrCapabilities;
+ std::unordered_map<ColorModeKey, ColorModeValue> mColorModes;
+};
+
+std::unique_ptr<compositionengine::DisplayColorProfile> createDisplayColorProfile(
+ DisplayColorProfileCreationArgs&&);
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
new file mode 100644
index 0000000..782c8d7
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <string>
+#include <type_traits>
+
+#include <math/mat4.h>
+#include <ui/FloatRect.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+
+namespace android::compositionengine::impl {
+
+void dumpVal(std::string& out, const char* name, bool);
+void dumpVal(std::string& out, const char* name, const void*);
+void dumpVal(std::string& out, const char* name, int);
+void dumpVal(std::string& out, const char* name, float);
+void dumpVal(std::string& out, const char* name, uint32_t);
+void dumpHex(std::string& out, const char* name, uint64_t);
+void dumpVal(std::string& out, const char* name, const char* value);
+void dumpVal(std::string& out, const char* name, const std::string& value);
+
+// For enums with named values
+void dumpVal(std::string& out, const char* name, const char*, int);
+void dumpVal(std::string& out, const char* name, const std::string&, int);
+
+template <typename EnumType>
+void dumpVal(std::string& out, const char* name, const char* valueName, EnumType value) {
+ dumpVal(out, name, valueName, static_cast<std::underlying_type_t<EnumType>>(value));
+}
+
+template <typename EnumType>
+void dumpVal(std::string& out, const char* name, const std::string& valueName, EnumType value) {
+ dumpVal(out, name, valueName, static_cast<std::underlying_type_t<EnumType>>(value));
+}
+
+void dumpVal(std::string& out, const char* name, const FloatRect& rect);
+void dumpVal(std::string& out, const char* name, const Rect& rect);
+void dumpVal(std::string& out, const char* name, const Region& region);
+void dumpVal(std::string& out, const char* name, const ui::Transform&);
+void dumpVal(std::string& out, const char* name, const ui::Size&);
+
+void dumpVal(std::string& out, const char* name, const mat4& tr);
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
new file mode 100644
index 0000000..521e1d7
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2019 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 <memory>
+
+#include <compositionengine/Output.h>
+#include <compositionengine/impl/OutputCompositionState.h>
+
+namespace android::compositionengine {
+
+class CompositionEngine;
+
+namespace impl {
+
+class Output : public virtual compositionengine::Output {
+public:
+ Output(const CompositionEngine&);
+ virtual ~Output();
+
+ bool isValid() const override;
+
+ void setCompositionEnabled(bool) override;
+ void setProjection(const ui::Transform&, int32_t orientation, const Rect& frame,
+ const Rect& viewport, const Rect& scissor, bool needsFiltering) override;
+ void setBounds(const ui::Size&) override;
+ void setLayerStackFilter(bool singleLayerStack, uint32_t singleLayerStackId) override;
+
+ void setColorTransform(const mat4&) override;
+ void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) override;
+
+ void dump(std::string&) const override;
+
+ const std::string& getName() const override;
+ void setName(const std::string&) override;
+
+ compositionengine::DisplayColorProfile* getDisplayColorProfile() const override;
+ void setDisplayColorProfile(std::unique_ptr<compositionengine::DisplayColorProfile>) override;
+
+ compositionengine::RenderSurface* getRenderSurface() const override;
+ void setRenderSurface(std::unique_ptr<compositionengine::RenderSurface>) override;
+
+ const OutputCompositionState& getState() const override;
+ OutputCompositionState& editState() override;
+
+ Region getPhysicalSpaceDirtyRegion(bool repaintEverything) const override;
+ bool belongsInOutput(uint32_t) const override;
+
+ // Testing
+ void setDisplayColorProfileForTest(std::unique_ptr<compositionengine::DisplayColorProfile>);
+ void setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface>);
+
+protected:
+ const CompositionEngine& getCompositionEngine() const;
+ void dumpBase(std::string&) const;
+
+private:
+ void dirtyEntireOutput();
+
+ const CompositionEngine& mCompositionEngine;
+
+ std::string mName;
+
+ OutputCompositionState mState;
+
+ std::unique_ptr<compositionengine::DisplayColorProfile> mDisplayColorProfile;
+ std::unique_ptr<compositionengine::RenderSurface> mRenderSurface;
+};
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
new file mode 100644
index 0000000..96a0e0f
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2019 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 <cstdint>
+
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+
+namespace android {
+
+namespace compositionengine::impl {
+
+struct OutputCompositionState {
+ // If false, composition will not per performed for this display
+ bool isEnabled{false};
+
+ // If false, this output is not considered secure
+ bool isSecure{false};
+
+ // If true, only layer stacks with a matching layerStack value will be
+ // displayed. If false, all layer stacks will be displayed.
+ bool singleLayerStack{true};
+
+ // The layer stack to display on this display
+ uint32_t singleLayerStackId{~0u};
+
+ // The physical space screen bounds
+ Rect bounds;
+
+ // The logical to physical transformation to use
+ ui::Transform transform;
+
+ // The physical orientation of the display, expressed as ui::Transform
+ // orientation flags.
+ uint32_t orientation{0};
+
+ // The logical space user visible bounds
+ Rect frame;
+
+ // The logical space user viewport rectangle
+ Rect viewport;
+
+ // The physical space scissor rectangle
+ Rect scissor;
+
+ // If true, RenderEngine filtering should be enabled
+ bool needsFiltering{false};
+
+ // The logical coordinates for the dirty region for the display.
+ // dirtyRegion is semi-persistent state. Dirty rectangles are added to it
+ // by the FE until composition happens, at which point it is cleared.
+ Region dirtyRegion;
+
+ // The logical coordinates for the undefined region for the display.
+ // The undefined region is internal to the composition engine. It is
+ // updated every time the geometry changes.
+ Region undefinedRegion;
+
+ // True if the last composition frame had visible layers
+ bool lastCompositionHadVisibleLayers{false};
+
+ // The color transform to apply
+ android_color_transform_t colorTransform{HAL_COLOR_TRANSFORM_IDENTITY};
+
+ // Current active color mode
+ ui::ColorMode colorMode{ui::ColorMode::NATIVE};
+
+ // Current active render intent
+ ui::RenderIntent renderIntent{ui::RenderIntent::COLORIMETRIC};
+
+ // Current active dstaspace
+ ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
+
+ // Debugging
+ void dump(std::string& result) const;
+};
+
+} // namespace compositionengine::impl
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
new file mode 100644
index 0000000..0489310
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2019 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 <memory>
+
+#include <android-base/unique_fd.h>
+#include <compositionengine/RenderSurface.h>
+#include <utils/StrongPointer.h>
+
+struct ANativeWindow;
+
+namespace android {
+
+namespace compositionengine {
+
+class CompositionEngine;
+class Display;
+class DisplaySurface;
+
+struct RenderSurfaceCreationArgs;
+
+namespace impl {
+
+class RenderSurface : public compositionengine::RenderSurface {
+public:
+ RenderSurface(const CompositionEngine&, compositionengine::Display&,
+ compositionengine::RenderSurfaceCreationArgs&&);
+ ~RenderSurface() override;
+
+ bool isValid() const override;
+ void initialize() override;
+ const ui::Size& getSize() const override;
+
+ const sp<Fence>& getClientTargetAcquireFence() const override;
+ void setBufferDataspace(ui::Dataspace) override;
+ void setDisplaySize(const ui::Size&) override;
+ void setProtected(bool useProtected) override;
+ status_t beginFrame(bool mustRecompose) override;
+ status_t prepareFrame(std::vector<CompositionInfo>& compositionData) override;
+ sp<GraphicBuffer> dequeueBuffer() override;
+ void queueBuffer() override;
+ void onPresentDisplayCompleted() override;
+ void finishBuffer() override;
+ void setViewportAndProjection() override;
+ void flip() override;
+
+ // Debugging
+ void dump(std::string& result) const override;
+ std::uint32_t getPageFlipCount() const override;
+
+ // Testing
+ void setPageFlipCountForTest(std::uint32_t);
+ void setSizeForTest(const ui::Size&);
+ sp<GraphicBuffer>& mutableGraphicBufferForTest();
+ base::unique_fd& mutableBufferReadyForTest();
+
+private:
+ const compositionengine::CompositionEngine& mCompositionEngine;
+ const compositionengine::Display& mDisplay;
+
+ // ANativeWindow being rendered into
+ const sp<ANativeWindow> mNativeWindow;
+ // Current buffer being rendered into
+ sp<GraphicBuffer> mGraphicBuffer;
+ // File descriptor indicating that mGraphicBuffer is ready for display, i.e.
+ // that drawing to the buffer is now complete.
+ base::unique_fd mBufferReady;
+ const sp<DisplaySurface> mDisplaySurface;
+ ui::Size mSize;
+ std::uint32_t mPageFlipCount{0};
+};
+
+std::unique_ptr<compositionengine::RenderSurface> createRenderSurface(
+ const compositionengine::CompositionEngine&, compositionengine::Display&,
+ compositionengine::RenderSurfaceCreationArgs&&);
+
+} // namespace impl
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
index 9ba213e..1967666 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
@@ -17,6 +17,7 @@
#pragma once
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/DisplayCreationArgs.h>
#include <gmock/gmock.h>
#include <renderengine/RenderEngine.h>
@@ -29,6 +30,8 @@
CompositionEngine();
~CompositionEngine() override;
+ MOCK_METHOD1(createDisplay, std::shared_ptr<Display>(DisplayCreationArgs&&));
+
MOCK_CONST_METHOD0(getHwComposer, HWComposer&());
MOCK_METHOD1(setHwComposer, void(std::unique_ptr<HWComposer>));
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
new file mode 100644
index 0000000..d763aa6
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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 <compositionengine/Display.h>
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/mock/Output.h>
+#include <gmock/gmock.h>
+#include <system/window.h>
+
+#include "DisplayHardware/DisplayIdentification.h"
+
+namespace android::compositionengine::mock {
+
+class Display : public compositionengine::mock::Output, public compositionengine::Display {
+public:
+ Display();
+ virtual ~Display();
+
+ MOCK_CONST_METHOD0(getId, const std::optional<DisplayId>&());
+ MOCK_CONST_METHOD0(isSecure, bool());
+ MOCK_CONST_METHOD0(isVirtual, bool());
+
+ MOCK_METHOD0(disconnect, void());
+
+ MOCK_METHOD1(createDisplayColorProfile, void(DisplayColorProfileCreationArgs&&));
+ MOCK_METHOD1(createRenderSurface, void(RenderSurfaceCreationArgs&&));
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
new file mode 100644
index 0000000..8056c9d
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2019 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 <compositionengine/DisplayColorProfile.h>
+#include <gmock/gmock.h>
+#include <ui/HdrCapabilities.h>
+
+namespace android::compositionengine::mock {
+
+class DisplayColorProfile : public compositionengine::DisplayColorProfile {
+public:
+ DisplayColorProfile();
+ ~DisplayColorProfile() override;
+
+ MOCK_CONST_METHOD0(isValid, bool());
+
+ MOCK_CONST_METHOD1(hasRenderIntent, bool(ui::RenderIntent));
+ MOCK_CONST_METHOD1(hasLegacyHdrSupport, bool(ui::Dataspace));
+ MOCK_CONST_METHOD5(getBestColorMode,
+ void(ui::Dataspace, ui::RenderIntent, ui::Dataspace*, ui::ColorMode*,
+ ui::RenderIntent*));
+ MOCK_CONST_METHOD0(hasWideColorGamut, bool());
+ MOCK_CONST_METHOD0(getSupportedPerFrameMetadata, int32_t());
+ MOCK_CONST_METHOD0(hasHDR10PlusSupport, bool());
+ MOCK_CONST_METHOD0(hasHDR10Support, bool());
+ MOCK_CONST_METHOD0(hasHLGSupport, bool());
+ MOCK_CONST_METHOD0(hasDolbyVisionSupport, bool());
+
+ MOCK_CONST_METHOD0(getHdrCapabilities, const HdrCapabilities&());
+
+ MOCK_CONST_METHOD1(dump, void(std::string&));
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
similarity index 81%
rename from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.h
rename to services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
index d6c9aa4..31b5f95 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -16,16 +16,13 @@
#pragma once
+#include <compositionengine/DisplaySurface.h>
#include <gmock/gmock.h>
-
#include <utils/String8.h>
-#include "DisplayHardware/DisplaySurface.h"
+namespace android::compositionengine::mock {
-namespace android {
-namespace mock {
-
-class DisplaySurface : public android::DisplaySurface {
+class DisplaySurface : public compositionengine::DisplaySurface {
public:
DisplaySurface();
~DisplaySurface() override;
@@ -39,5 +36,4 @@
MOCK_CONST_METHOD0(getClientTargetAcquireFence, const sp<Fence>&());
};
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
new file mode 100644
index 0000000..37f7007
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 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 <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/Output.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/OutputCompositionState.h>
+#include <gmock/gmock.h>
+
+namespace android::compositionengine::mock {
+
+class Output : public virtual compositionengine::Output {
+public:
+ Output();
+ virtual ~Output();
+
+ MOCK_CONST_METHOD0(isValid, bool());
+
+ MOCK_METHOD1(setCompositionEnabled, void(bool));
+ MOCK_METHOD6(setProjection,
+ void(const ui::Transform&, int32_t, const Rect&, const Rect&, const Rect&, bool));
+ MOCK_METHOD1(setBounds, void(const ui::Size&));
+ MOCK_METHOD2(setLayerStackFilter, void(bool, uint32_t));
+
+ MOCK_METHOD1(setColorTransform, void(const mat4&));
+ MOCK_METHOD3(setColorMode, void(ui::ColorMode, ui::Dataspace, ui::RenderIntent));
+
+ MOCK_CONST_METHOD1(dump, void(std::string&));
+ MOCK_CONST_METHOD0(getName, const std::string&());
+ MOCK_METHOD1(setName, void(const std::string&));
+
+ MOCK_CONST_METHOD0(getDisplayColorProfile, DisplayColorProfile*());
+ MOCK_METHOD1(setDisplayColorProfile, void(std::unique_ptr<DisplayColorProfile>));
+
+ MOCK_CONST_METHOD0(getRenderSurface, RenderSurface*());
+ MOCK_METHOD1(setRenderSurface, void(std::unique_ptr<RenderSurface>));
+
+ MOCK_CONST_METHOD0(getState, const OutputCompositionState&());
+ MOCK_METHOD0(editState, OutputCompositionState&());
+
+ MOCK_CONST_METHOD1(getPhysicalSpaceDirtyRegion, Region(bool));
+ MOCK_CONST_METHOD1(belongsInOutput, bool(uint32_t));
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
new file mode 100644
index 0000000..2269e57
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 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 <compositionengine/RenderSurface.h>
+#include <gmock/gmock.h>
+#include <ui/GraphicBuffer.h>
+
+#include "LayerBE.h"
+
+namespace android::compositionengine::mock {
+
+class RenderSurface : public compositionengine::RenderSurface {
+public:
+ RenderSurface();
+ ~RenderSurface() override;
+
+ MOCK_CONST_METHOD0(isValid, bool());
+ MOCK_METHOD0(initialize, void());
+ MOCK_CONST_METHOD0(getSize, const ui::Size&());
+ MOCK_CONST_METHOD0(getClientTargetAcquireFence, const sp<Fence>&());
+ MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
+ MOCK_METHOD1(setProtected, void(bool));
+ MOCK_METHOD1(setBufferDataspace, void(ui::Dataspace));
+ MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
+ MOCK_METHOD1(prepareFrame, status_t(std::vector<CompositionInfo>& compositionData));
+ MOCK_METHOD0(dequeueBuffer, sp<GraphicBuffer>());
+ MOCK_METHOD0(queueBuffer, void());
+ MOCK_METHOD0(onPresentDisplayCompleted, void());
+ MOCK_METHOD0(finishBuffer, void());
+ MOCK_METHOD0(setViewportAndProjection, void());
+ MOCK_METHOD0(flip, void());
+ MOCK_CONST_METHOD1(dump, void(std::string& result));
+ MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t());
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/mock/Display.cpp
similarity index 60%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/mock/Display.cpp
index e6ac6bf..01cf112 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/Display.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <compositionengine/mock/Display.h>
-namespace android {
-namespace mock {
+namespace android::compositionengine::mock {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+Display::Display() = default;
+Display::~Display() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/mock/DisplayColorProfile.cpp
similarity index 66%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/mock/DisplayColorProfile.cpp
index e6ac6bf..581d1f7 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/DisplayColorProfile.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
- *
+ * Copyright 2019 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
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <compositionengine/mock/DisplayColorProfile.h>
-namespace android {
-namespace mock {
+namespace android::compositionengine::mock {
// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+DisplayColorProfile::DisplayColorProfile() = default;
+DisplayColorProfile::~DisplayColorProfile() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/mock/DisplaySurface.cpp
similarity index 67%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/mock/DisplaySurface.cpp
index e6ac6bf..bbbd7c1 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/DisplaySurface.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include "compositionengine/mock/DisplaySurface.h"
-namespace android {
-namespace mock {
+namespace android::compositionengine::mock {
-// Explicit default instantiation is recommended.
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
DisplaySurface::DisplaySurface() = default;
DisplaySurface::~DisplaySurface() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/mock/Output.cpp
similarity index 60%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/mock/Output.cpp
index e6ac6bf..44df4c3 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/Output.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <compositionengine/mock/Output.h>
-namespace android {
-namespace mock {
+namespace android::compositionengine::mock {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+Output::Output() = default;
+Output::~Output() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/mock/RenderSurface.cpp
similarity index 68%
copy from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
copy to services/surfaceflinger/CompositionEngine/mock/RenderSurface.cpp
index e6ac6bf..fe718d6 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/mock/RenderSurface.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
- *
+ * Copyright 2019 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
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <compositionengine/mock/RenderSurface.h>
-namespace android {
-namespace mock {
+namespace android::compositionengine::mock {
// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
-DisplaySurface::~DisplaySurface() = default;
+RenderSurface::RenderSurface() = default;
+RenderSurface::~RenderSurface() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index fbf71b5..127d729 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -15,6 +15,7 @@
*/
#include <compositionengine/impl/CompositionEngine.h>
+#include <compositionengine/impl/Display.h>
#include <renderengine/RenderEngine.h>
#include "DisplayHardware/HWComposer.h"
@@ -32,6 +33,11 @@
CompositionEngine::CompositionEngine() = default;
CompositionEngine::~CompositionEngine() = default;
+std::shared_ptr<compositionengine::Display> CompositionEngine::createDisplay(
+ DisplayCreationArgs&& args) {
+ return compositionengine::impl::createDisplay(*this, std::move(args));
+}
+
HWComposer& CompositionEngine::getHwComposer() const {
return *mHwComposer.get();
}
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
new file mode 100644
index 0000000..f9d70e3
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2019 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 <android-base/stringprintf.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/DisplayCreationArgs.h>
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/impl/Display.h>
+#include <compositionengine/impl/DisplayColorProfile.h>
+#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/RenderSurface.h>
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android::compositionengine::impl {
+
+std::shared_ptr<compositionengine::Display> createDisplay(
+ const compositionengine::CompositionEngine& compositionEngine,
+ compositionengine::DisplayCreationArgs&& args) {
+ return std::make_shared<Display>(compositionEngine, std::move(args));
+}
+
+Display::Display(const CompositionEngine& compositionEngine, DisplayCreationArgs&& args)
+ : compositionengine::impl::Output(compositionEngine),
+ mIsVirtual(args.isVirtual),
+ mId(args.displayId) {
+ editState().isSecure = args.isSecure;
+}
+
+Display::~Display() = default;
+
+const std::optional<DisplayId>& Display::getId() const {
+ return mId;
+}
+
+bool Display::isSecure() const {
+ return getState().isSecure;
+}
+
+bool Display::isVirtual() const {
+ return mIsVirtual;
+}
+
+void Display::disconnect() {
+ if (!mId) {
+ return;
+ }
+
+ auto& hwc = getCompositionEngine().getHwComposer();
+ hwc.disconnectDisplay(*mId);
+ mId.reset();
+}
+
+void Display::setColorTransform(const mat4& transform) {
+ Output::setColorTransform(transform);
+
+ auto& hwc = getCompositionEngine().getHwComposer();
+ status_t result = hwc.setColorTransform(*mId, transform);
+ ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display \"%s\": %d",
+ mId ? to_string(*mId).c_str() : "", result);
+}
+
+void Display::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
+ ui::RenderIntent renderIntent) {
+ if (mode == getState().colorMode && dataspace == getState().dataspace &&
+ renderIntent == getState().renderIntent) {
+ return;
+ }
+
+ if (mIsVirtual) {
+ ALOGW("%s: Invalid operation on virtual display", __FUNCTION__);
+ return;
+ }
+
+ Output::setColorMode(mode, dataspace, renderIntent);
+
+ auto& hwc = getCompositionEngine().getHwComposer();
+ hwc.setActiveColorMode(*mId, mode, renderIntent);
+}
+
+void Display::dump(std::string& out) const {
+ using android::base::StringAppendF;
+
+ StringAppendF(&out, " Composition Display State: [\"%s\"]", getName().c_str());
+
+ out.append("\n ");
+
+ dumpVal(out, "isVirtual", mIsVirtual);
+ if (mId) {
+ dumpVal(out, "hwcId", to_string(*mId));
+ } else {
+ StringAppendF(&out, "no hwcId, ");
+ }
+
+ out.append("\n");
+
+ Output::dumpBase(out);
+}
+
+void Display::createDisplayColorProfile(DisplayColorProfileCreationArgs&& args) {
+ setDisplayColorProfile(compositionengine::impl::createDisplayColorProfile(std::move(args)));
+}
+
+void Display::createRenderSurface(RenderSurfaceCreationArgs&& args) {
+ setRenderSurface(compositionengine::impl::createRenderSurface(getCompositionEngine(), *this,
+ std::move(args)));
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
new file mode 100644
index 0000000..6e6f3c0
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
@@ -0,0 +1,395 @@
+/*
+ * Copyright 2019 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 <array>
+#include <unordered_set>
+
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/DisplayColorProfile.h>
+#include <compositionengine/impl/DumpHelpers.h>
+#include <log/log.h>
+#include <ui/DebugUtils.h>
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android::compositionengine {
+
+DisplayColorProfile::~DisplayColorProfile() = default;
+
+namespace impl {
+namespace {
+
+using ui::ColorMode;
+using ui::Dataspace;
+using ui::RenderIntent;
+
+// ordered list of known SDR color modes
+const std::array<ColorMode, 3> sSdrColorModes = {
+ ColorMode::DISPLAY_BT2020,
+ ColorMode::DISPLAY_P3,
+ ColorMode::SRGB,
+};
+
+// ordered list of known HDR color modes
+const std::array<ColorMode, 2> sHdrColorModes = {
+ ColorMode::BT2100_PQ,
+ ColorMode::BT2100_HLG,
+};
+
+// ordered list of known SDR render intents
+const std::array<RenderIntent, 2> sSdrRenderIntents = {
+ RenderIntent::ENHANCE,
+ RenderIntent::COLORIMETRIC,
+};
+
+// ordered list of known HDR render intents
+const std::array<RenderIntent, 2> sHdrRenderIntents = {
+ RenderIntent::TONE_MAP_ENHANCE,
+ RenderIntent::TONE_MAP_COLORIMETRIC,
+};
+
+// map known color mode to dataspace
+Dataspace colorModeToDataspace(ColorMode mode) {
+ switch (mode) {
+ case ColorMode::SRGB:
+ return Dataspace::V0_SRGB;
+ case ColorMode::DISPLAY_P3:
+ return Dataspace::DISPLAY_P3;
+ case ColorMode::DISPLAY_BT2020:
+ return Dataspace::DISPLAY_BT2020;
+ case ColorMode::BT2100_HLG:
+ return Dataspace::BT2020_HLG;
+ case ColorMode::BT2100_PQ:
+ return Dataspace::BT2020_PQ;
+ default:
+ return Dataspace::UNKNOWN;
+ }
+}
+
+// Return a list of candidate color modes.
+std::vector<ColorMode> getColorModeCandidates(ColorMode mode) {
+ std::vector<ColorMode> candidates;
+
+ // add mode itself
+ candidates.push_back(mode);
+
+ // check if mode is HDR
+ bool isHdr = false;
+ for (auto hdrMode : sHdrColorModes) {
+ if (hdrMode == mode) {
+ isHdr = true;
+ break;
+ }
+ }
+
+ // add other HDR candidates when mode is HDR
+ if (isHdr) {
+ for (auto hdrMode : sHdrColorModes) {
+ if (hdrMode != mode) {
+ candidates.push_back(hdrMode);
+ }
+ }
+ }
+
+ // add other SDR candidates
+ for (auto sdrMode : sSdrColorModes) {
+ if (sdrMode != mode) {
+ candidates.push_back(sdrMode);
+ }
+ }
+
+ return candidates;
+}
+
+// Return a list of candidate render intents.
+std::vector<RenderIntent> getRenderIntentCandidates(RenderIntent intent) {
+ std::vector<RenderIntent> candidates;
+
+ // add intent itself
+ candidates.push_back(intent);
+
+ // check if intent is HDR
+ bool isHdr = false;
+ for (auto hdrIntent : sHdrRenderIntents) {
+ if (hdrIntent == intent) {
+ isHdr = true;
+ break;
+ }
+ }
+
+ if (isHdr) {
+ // add other HDR candidates when intent is HDR
+ for (auto hdrIntent : sHdrRenderIntents) {
+ if (hdrIntent != intent) {
+ candidates.push_back(hdrIntent);
+ }
+ }
+ } else {
+ // add other SDR candidates when intent is SDR
+ for (auto sdrIntent : sSdrRenderIntents) {
+ if (sdrIntent != intent) {
+ candidates.push_back(sdrIntent);
+ }
+ }
+ }
+
+ return candidates;
+}
+
+// Return the best color mode supported by HWC.
+ColorMode getHwcColorMode(
+ const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes,
+ ColorMode mode) {
+ std::vector<ColorMode> candidates = getColorModeCandidates(mode);
+ for (auto candidate : candidates) {
+ auto iter = hwcColorModes.find(candidate);
+ if (iter != hwcColorModes.end()) {
+ return candidate;
+ }
+ }
+
+ return ColorMode::NATIVE;
+}
+
+// Return the best render intent supported by HWC.
+RenderIntent getHwcRenderIntent(const std::vector<RenderIntent>& hwcIntents, RenderIntent intent) {
+ std::vector<RenderIntent> candidates = getRenderIntentCandidates(intent);
+ for (auto candidate : candidates) {
+ for (auto hwcIntent : hwcIntents) {
+ if (candidate == hwcIntent) {
+ return candidate;
+ }
+ }
+ }
+
+ return RenderIntent::COLORIMETRIC;
+}
+
+} // anonymous namespace
+
+std::unique_ptr<compositionengine::DisplayColorProfile> createDisplayColorProfile(
+ DisplayColorProfileCreationArgs&& args) {
+ return std::make_unique<DisplayColorProfile>(std::move(args));
+}
+
+DisplayColorProfile::DisplayColorProfile(DisplayColorProfileCreationArgs&& args)
+ : mHasWideColorGamut(args.hasWideColorGamut),
+ mSupportedPerFrameMetadata(args.supportedPerFrameMetadata) {
+ populateColorModes(args.hwcColorModes);
+
+ std::vector<ui::Hdr> types = args.hdrCapabilities.getSupportedHdrTypes();
+ for (ui::Hdr hdrType : types) {
+ switch (hdrType) {
+ case ui::Hdr::HDR10_PLUS:
+ mHasHdr10Plus = true;
+ break;
+ case ui::Hdr::HDR10:
+ mHasHdr10 = true;
+ break;
+ case ui::Hdr::HLG:
+ mHasHLG = true;
+ break;
+ case ui::Hdr::DOLBY_VISION:
+ mHasDolbyVision = true;
+ break;
+ default:
+ ALOGE("UNKNOWN HDR capability: %d", static_cast<int32_t>(hdrType));
+ }
+ }
+
+ float minLuminance = args.hdrCapabilities.getDesiredMinLuminance();
+ float maxLuminance = args.hdrCapabilities.getDesiredMaxLuminance();
+ float maxAverageLuminance = args.hdrCapabilities.getDesiredMaxAverageLuminance();
+
+ minLuminance = minLuminance <= 0.0 ? sDefaultMinLumiance : minLuminance;
+ maxLuminance = maxLuminance <= 0.0 ? sDefaultMaxLumiance : maxLuminance;
+ maxAverageLuminance = maxAverageLuminance <= 0.0 ? sDefaultMaxLumiance : maxAverageLuminance;
+ if (args.hasWideColorGamut) {
+ // insert HDR10/HLG as we will force client composition for HDR10/HLG
+ // layers
+ if (!hasHDR10Support()) {
+ types.push_back(ui::Hdr::HDR10);
+ }
+
+ if (!hasHLGSupport()) {
+ types.push_back(ui::Hdr::HLG);
+ }
+ }
+
+ mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
+}
+
+DisplayColorProfile::~DisplayColorProfile() = default;
+
+bool DisplayColorProfile::isValid() const {
+ return true;
+}
+
+bool DisplayColorProfile::hasWideColorGamut() const {
+ return mHasWideColorGamut;
+}
+
+int32_t DisplayColorProfile::getSupportedPerFrameMetadata() const {
+ return mSupportedPerFrameMetadata;
+}
+
+bool DisplayColorProfile::hasHDR10PlusSupport() const {
+ return mHasHdr10Plus;
+}
+
+bool DisplayColorProfile::hasHDR10Support() const {
+ return mHasHdr10;
+}
+
+bool DisplayColorProfile::hasHLGSupport() const {
+ return mHasHLG;
+}
+
+bool DisplayColorProfile::hasDolbyVisionSupport() const {
+ return mHasDolbyVision;
+}
+
+const HdrCapabilities& DisplayColorProfile::getHdrCapabilities() const {
+ return mHdrCapabilities;
+}
+
+void DisplayColorProfile::populateColorModes(
+ const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes) {
+ if (!hasWideColorGamut()) {
+ return;
+ }
+
+ // collect all known SDR render intents
+ std::unordered_set<RenderIntent> sdrRenderIntents(sSdrRenderIntents.begin(),
+ sSdrRenderIntents.end());
+ auto iter = hwcColorModes.find(ColorMode::SRGB);
+ if (iter != hwcColorModes.end()) {
+ for (auto intent : iter->second) {
+ sdrRenderIntents.insert(intent);
+ }
+ }
+
+ // add all known SDR combinations
+ for (auto intent : sdrRenderIntents) {
+ for (auto mode : sSdrColorModes) {
+ addColorMode(hwcColorModes, mode, intent);
+ }
+ }
+
+ // collect all known HDR render intents
+ std::unordered_set<RenderIntent> hdrRenderIntents(sHdrRenderIntents.begin(),
+ sHdrRenderIntents.end());
+ iter = hwcColorModes.find(ColorMode::BT2100_PQ);
+ if (iter != hwcColorModes.end()) {
+ for (auto intent : iter->second) {
+ hdrRenderIntents.insert(intent);
+ }
+ }
+
+ // add all known HDR combinations
+ for (auto intent : sHdrRenderIntents) {
+ for (auto mode : sHdrColorModes) {
+ addColorMode(hwcColorModes, mode, intent);
+ }
+ }
+}
+
+// Map dataspace/intent to the best matched dataspace/colorMode/renderIntent
+// supported by HWC.
+void DisplayColorProfile::addColorMode(
+ const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes, const ColorMode mode,
+ const RenderIntent intent) {
+ // find the best color mode
+ const ColorMode hwcColorMode = getHwcColorMode(hwcColorModes, mode);
+
+ // find the best render intent
+ auto iter = hwcColorModes.find(hwcColorMode);
+ const auto& hwcIntents =
+ iter != hwcColorModes.end() ? iter->second : std::vector<RenderIntent>();
+ const RenderIntent hwcIntent = getHwcRenderIntent(hwcIntents, intent);
+
+ const Dataspace dataspace = colorModeToDataspace(mode);
+ const Dataspace hwcDataspace = colorModeToDataspace(hwcColorMode);
+
+ ALOGV("DisplayColorProfile: map (%s, %s) to (%s, %s, %s)",
+ dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
+ decodeRenderIntent(intent).c_str(),
+ dataspaceDetails(static_cast<android_dataspace_t>(hwcDataspace)).c_str(),
+ decodeColorMode(hwcColorMode).c_str(), decodeRenderIntent(hwcIntent).c_str());
+
+ mColorModes[getColorModeKey(dataspace, intent)] = {hwcDataspace, hwcColorMode, hwcIntent};
+}
+
+bool DisplayColorProfile::hasRenderIntent(RenderIntent intent) const {
+ // assume a render intent is supported when SRGB supports it; we should
+ // get rid of that assumption.
+ auto iter = mColorModes.find(getColorModeKey(Dataspace::V0_SRGB, intent));
+ return iter != mColorModes.end() && iter->second.renderIntent == intent;
+}
+
+bool DisplayColorProfile::hasLegacyHdrSupport(Dataspace dataspace) const {
+ if ((dataspace == Dataspace::BT2020_PQ && hasHDR10Support()) ||
+ (dataspace == Dataspace::BT2020_HLG && hasHLGSupport())) {
+ auto iter =
+ mColorModes.find(getColorModeKey(dataspace, RenderIntent::TONE_MAP_COLORIMETRIC));
+ return iter == mColorModes.end() || iter->second.dataspace != dataspace;
+ }
+
+ return false;
+}
+
+void DisplayColorProfile::getBestColorMode(Dataspace dataspace, RenderIntent intent,
+ Dataspace* outDataspace, ColorMode* outMode,
+ RenderIntent* outIntent) const {
+ auto iter = mColorModes.find(getColorModeKey(dataspace, intent));
+ if (iter != mColorModes.end()) {
+ *outDataspace = iter->second.dataspace;
+ *outMode = iter->second.colorMode;
+ *outIntent = iter->second.renderIntent;
+ } else {
+ // this is unexpected on a WCG display
+ if (hasWideColorGamut()) {
+ ALOGE("map unknown (%s)/(%s) to default color mode",
+ dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
+ decodeRenderIntent(intent).c_str());
+ }
+
+ *outDataspace = Dataspace::UNKNOWN;
+ *outMode = ColorMode::NATIVE;
+ *outIntent = RenderIntent::COLORIMETRIC;
+ }
+}
+
+void DisplayColorProfile::dump(std::string& out) const {
+ out.append(" Composition Display Color State:");
+
+ out.append("\n HWC Support: ");
+
+ dumpVal(out, "wideColorGamut", hasWideColorGamut());
+ dumpVal(out, "hdr10plus", hasHDR10PlusSupport());
+ dumpVal(out, "hdr10", hasHDR10Support());
+ dumpVal(out, "hlg", hasHLGSupport());
+ dumpVal(out, "dv", hasDolbyVisionSupport());
+ dumpVal(out, "metadata", getSupportedPerFrameMetadata());
+
+ out.append("\n");
+}
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
similarity index 68%
rename from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
rename to services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
index e6ac6bf..db6d4f2 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplaySurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -14,14 +14,10 @@
* limitations under the License.
*/
-#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include <compositionengine/DisplaySurface.h>
-namespace android {
-namespace mock {
+namespace android::compositionengine {
-// Explicit default instantiation is recommended.
-DisplaySurface::DisplaySurface() = default;
DisplaySurface::~DisplaySurface() = default;
-} // namespace mock
-} // namespace android
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
new file mode 100644
index 0000000..c497013
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2019 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 <cinttypes>
+
+#include <android-base/stringprintf.h>
+#include <compositionengine/impl/DumpHelpers.h>
+
+namespace android::compositionengine::impl {
+
+using android::base::StringAppendF;
+
+void dumpVal(std::string& out, const char* name, bool value) {
+ StringAppendF(&out, "%s=%c ", name, value ? 'T' : 'F');
+}
+
+void dumpVal(std::string& out, const char* name, const void* value) {
+ StringAppendF(&out, "%s=%p ", name, value);
+}
+
+void dumpVal(std::string& out, const char* name, int value) {
+ StringAppendF(&out, "%s=%d ", name, value);
+}
+
+void dumpVal(std::string& out, const char* name, float value) {
+ StringAppendF(&out, "%s=%f ", name, value);
+}
+
+void dumpVal(std::string& out, const char* name, uint32_t value) {
+ StringAppendF(&out, "%s=%u ", name, value);
+}
+
+void dumpHex(std::string& out, const char* name, uint64_t value) {
+ StringAppendF(&out, "%s=0x08%" PRIx64 " ", name, value);
+}
+
+void dumpVal(std::string& out, const char* name, const char* value) {
+ StringAppendF(&out, "%s=%s ", name, value);
+}
+
+void dumpVal(std::string& out, const char* name, const std::string& value) {
+ dumpVal(out, name, value.c_str());
+}
+
+void dumpVal(std::string& out, const char* name, const char* valueName, int value) {
+ StringAppendF(&out, "%s=%s (%d)", name, valueName, value);
+}
+
+void dumpVal(std::string& out, const char* name, const std::string& valueName, int value) {
+ dumpVal(out, name, valueName.c_str(), value);
+}
+
+void dumpVal(std::string& out, const char* name, const FloatRect& rect) {
+ StringAppendF(&out, "%s=[%f %f %f %f] ", name, rect.left, rect.top, rect.right, rect.bottom);
+}
+
+void dumpVal(std::string& out, const char* name, const Rect& rect) {
+ StringAppendF(&out, "%s=[%d %d %d %d] ", name, rect.left, rect.top, rect.right, rect.bottom);
+}
+
+void dumpVal(std::string& out, const char* name, const Region& region) {
+ region.dump(out, name, 0);
+}
+
+void dumpVal(std::string& out, const char* name, const ui::Transform& transform) {
+ transform.dump(out, name);
+}
+
+void dumpVal(std::string& out, const char* name, const ui::Size& size) {
+ StringAppendF(&out, "%s=[%d %d] ", name, size.width, size.height);
+}
+
+void dumpVal(std::string& out, const char* name, const mat4& tr) {
+ StringAppendF(&out,
+ "%s=["
+ /* clang-format off */
+ "[%0.3f,%0.3f,%0.3f,%0.3f]"
+ "[%0.3f,%0.3f,%0.3f,%0.3f]"
+ "[%0.3f,%0.3f,%0.3f,%0.3f]"
+ "[%0.3f,%0.3f,%0.3f,%0.3f]]",
+ name,
+ tr[0][0], tr[1][0], tr[2][0], tr[3][0],
+ tr[0][1], tr[1][1], tr[2][1], tr[3][1],
+ tr[0][2], tr[1][2], tr[2][2], tr[3][2],
+ tr[0][3], tr[1][3], tr[2][3], tr[3][3]
+ ); /* clang-format on */
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
new file mode 100644
index 0000000..dbf77b0
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2019 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 <android-base/stringprintf.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/Output.h>
+#include <ui/DebugUtils.h>
+
+namespace android::compositionengine::impl {
+
+Output::Output(const CompositionEngine& compositionEngine)
+ : mCompositionEngine(compositionEngine) {}
+
+Output::~Output() = default;
+
+const CompositionEngine& Output::getCompositionEngine() const {
+ return mCompositionEngine;
+}
+
+bool Output::isValid() const {
+ return mDisplayColorProfile && mDisplayColorProfile->isValid() && mRenderSurface &&
+ mRenderSurface->isValid();
+}
+
+const std::string& Output::getName() const {
+ return mName;
+}
+
+void Output::setName(const std::string& name) {
+ mName = name;
+}
+
+void Output::setCompositionEnabled(bool enabled) {
+ if (mState.isEnabled == enabled) {
+ return;
+ }
+
+ mState.isEnabled = enabled;
+ dirtyEntireOutput();
+}
+
+void Output::setProjection(const ui::Transform& transform, int32_t orientation, const Rect& frame,
+ const Rect& viewport, const Rect& scissor, bool needsFiltering) {
+ mState.transform = transform;
+ mState.orientation = orientation;
+ mState.scissor = scissor;
+ mState.frame = frame;
+ mState.viewport = viewport;
+ mState.needsFiltering = needsFiltering;
+
+ dirtyEntireOutput();
+}
+
+// TODO(lpique): Rename setSize() once more is moved.
+void Output::setBounds(const ui::Size& size) {
+ mRenderSurface->setDisplaySize(size);
+ // TODO(lpique): Rename mState.size once more is moved.
+ mState.bounds = Rect(mRenderSurface->getSize());
+
+ dirtyEntireOutput();
+}
+
+void Output::setLayerStackFilter(bool singleLayerStack, uint32_t singleLayerStackId) {
+ mState.singleLayerStack = singleLayerStack;
+ mState.singleLayerStackId = singleLayerStackId;
+
+ dirtyEntireOutput();
+}
+
+void Output::setColorTransform(const mat4& transform) {
+ const bool isIdentity = (transform == mat4());
+
+ mState.colorTransform =
+ isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
+}
+
+void Output::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
+ ui::RenderIntent renderIntent) {
+ mState.colorMode = mode;
+ mState.dataspace = dataspace;
+ mState.renderIntent = renderIntent;
+
+ mRenderSurface->setBufferDataspace(dataspace);
+
+ ALOGV("Set active color mode: %s (%d), active render intent: %s (%d)",
+ decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
+ renderIntent);
+}
+
+void Output::dump(std::string& out) const {
+ using android::base::StringAppendF;
+
+ StringAppendF(&out, " Composition Output State: [\"%s\"]", mName.c_str());
+
+ out.append("\n ");
+
+ dumpBase(out);
+}
+
+void Output::dumpBase(std::string& out) const {
+ mState.dump(out);
+
+ if (mDisplayColorProfile) {
+ mDisplayColorProfile->dump(out);
+ } else {
+ out.append(" No display color profile!\n");
+ }
+
+ if (mRenderSurface) {
+ mRenderSurface->dump(out);
+ } else {
+ out.append(" No render surface!\n");
+ }
+}
+
+compositionengine::DisplayColorProfile* Output::getDisplayColorProfile() const {
+ return mDisplayColorProfile.get();
+}
+
+void Output::setDisplayColorProfile(std::unique_ptr<compositionengine::DisplayColorProfile> mode) {
+ mDisplayColorProfile = std::move(mode);
+}
+
+void Output::setDisplayColorProfileForTest(
+ std::unique_ptr<compositionengine::DisplayColorProfile> mode) {
+ mDisplayColorProfile = std::move(mode);
+}
+
+compositionengine::RenderSurface* Output::getRenderSurface() const {
+ return mRenderSurface.get();
+}
+
+void Output::setRenderSurface(std::unique_ptr<compositionengine::RenderSurface> surface) {
+ mRenderSurface = std::move(surface);
+ mState.bounds = Rect(mRenderSurface->getSize());
+
+ dirtyEntireOutput();
+}
+
+void Output::setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface> surface) {
+ mRenderSurface = std::move(surface);
+}
+
+const OutputCompositionState& Output::getState() const {
+ return mState;
+}
+
+OutputCompositionState& Output::editState() {
+ return mState;
+}
+
+Region Output::getPhysicalSpaceDirtyRegion(bool repaintEverything) const {
+ Region dirty;
+ if (repaintEverything) {
+ dirty.set(mState.bounds);
+ } else {
+ dirty = mState.transform.transform(mState.dirtyRegion);
+ dirty.andSelf(mState.bounds);
+ }
+ return dirty;
+}
+
+bool Output::belongsInOutput(uint32_t layerStackId) const {
+ return !mState.singleLayerStack || (layerStackId == mState.singleLayerStackId);
+}
+
+void Output::dirtyEntireOutput() {
+ mState.dirtyRegion.set(mState.bounds);
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
new file mode 100644
index 0000000..7d8765f
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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 <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/OutputCompositionState.h>
+
+namespace android::compositionengine::impl {
+
+void OutputCompositionState::dump(std::string& out) const {
+ dumpVal(out, "isEnabled", isEnabled);
+ dumpVal(out, "isSecure", isSecure);
+ if (singleLayerStack) {
+ out.append("layerStack=<any>");
+ } else {
+ dumpVal(out, "layerStack", singleLayerStackId);
+ }
+
+ out.append("\n ");
+
+ dumpVal(out, "transform", transform);
+
+ out.append("\n ");
+
+ dumpVal(out, "frame", frame);
+ dumpVal(out, "viewport", viewport);
+ dumpVal(out, "scissor", scissor);
+ dumpVal(out, "needsFiltering", needsFiltering);
+
+ out.append("\n");
+
+ dumpVal(out, "colorMode", toString(colorMode), colorMode);
+ dumpVal(out, "renderIntent", toString(renderIntent), renderIntent);
+ dumpVal(out, "dataspace", toString(dataspace), dataspace);
+ dumpVal(out, "colorTransform", colorTransform);
+
+ out.append("\n");
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
new file mode 100644
index 0000000..d546fc8
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2019 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 <android-base/stringprintf.h>
+#include <android/native_window.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/RenderSurface.h>
+#include <log/log.h>
+#include <renderengine/RenderEngine.h>
+#include <sync/sync.h>
+#include <system/window.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+
+#include "DisplayHardware/HWComposer.h"
+
+namespace android::compositionengine {
+
+RenderSurface::~RenderSurface() = default;
+
+namespace impl {
+
+std::unique_ptr<compositionengine::RenderSurface> createRenderSurface(
+ const compositionengine::CompositionEngine& compositionEngine,
+ compositionengine::Display& display, compositionengine::RenderSurfaceCreationArgs&& args) {
+ return std::make_unique<RenderSurface>(compositionEngine, display, std::move(args));
+}
+
+RenderSurface::RenderSurface(const CompositionEngine& compositionEngine, Display& display,
+ RenderSurfaceCreationArgs&& args)
+ : mCompositionEngine(compositionEngine),
+ mDisplay(display),
+ mNativeWindow(args.nativeWindow),
+ mDisplaySurface(args.displaySurface),
+ mSize(args.displayWidth, args.displayHeight) {}
+
+RenderSurface::~RenderSurface() = default;
+
+bool RenderSurface::isValid() const {
+ return mSize.isValid();
+}
+
+void RenderSurface::initialize() {
+ ANativeWindow* const window = mNativeWindow.get();
+
+ int status = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+ ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status);
+ status = native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
+ ALOGE_IF(status != NO_ERROR, "Unable to set BQ format to RGBA888: %d", status);
+ status = native_window_set_usage(window, GRALLOC_USAGE_HW_RENDER);
+ ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for GPU rendering: %d", status);
+}
+
+const ui::Size& RenderSurface::getSize() const {
+ return mSize;
+}
+
+const sp<Fence>& RenderSurface::getClientTargetAcquireFence() const {
+ return mDisplaySurface->getClientTargetAcquireFence();
+}
+
+void RenderSurface::setDisplaySize(const ui::Size& size) {
+ mDisplaySurface->resizeBuffers(size.width, size.height);
+ mSize = size;
+}
+
+void RenderSurface::setBufferDataspace(ui::Dataspace dataspace) {
+ native_window_set_buffers_data_space(mNativeWindow.get(),
+ static_cast<android_dataspace>(dataspace));
+}
+
+void RenderSurface::setProtected(bool useProtected) {
+ uint64_t usageFlags = GRALLOC_USAGE_HW_RENDER;
+ if (useProtected) {
+ usageFlags |= GRALLOC_USAGE_PROTECTED;
+ }
+ const int status = native_window_set_usage(mNativeWindow.get(), usageFlags);
+ ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for protected content: %d", status);
+}
+
+status_t RenderSurface::beginFrame(bool mustRecompose) {
+ return mDisplaySurface->beginFrame(mustRecompose);
+}
+
+status_t RenderSurface::prepareFrame(std::vector<CompositionInfo>& compositionData) {
+ auto& hwc = mCompositionEngine.getHwComposer();
+ const auto id = mDisplay.getId();
+ if (id) {
+ status_t error = hwc.prepare(*id, compositionData);
+ if (error != NO_ERROR) {
+ return error;
+ }
+ }
+
+ DisplaySurface::CompositionType compositionType;
+ const bool hasClient = hwc.hasClientComposition(id);
+ const bool hasDevice = hwc.hasDeviceComposition(id);
+ if (hasClient && hasDevice) {
+ compositionType = DisplaySurface::COMPOSITION_MIXED;
+ } else if (hasClient) {
+ compositionType = DisplaySurface::COMPOSITION_GLES;
+ } else if (hasDevice) {
+ compositionType = DisplaySurface::COMPOSITION_HWC;
+ } else {
+ // Nothing to do -- when turning the screen off we get a frame like
+ // this. Call it a HWC frame since we won't be doing any GLES work but
+ // will do a prepare/set cycle.
+ compositionType = DisplaySurface::COMPOSITION_HWC;
+ }
+ return mDisplaySurface->prepareFrame(compositionType);
+}
+
+sp<GraphicBuffer> RenderSurface::dequeueBuffer() {
+ int fd = -1;
+ ANativeWindowBuffer* buffer = nullptr;
+
+ status_t result = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fd);
+
+ if (result != NO_ERROR) {
+ ALOGE("ANativeWindow::dequeueBuffer failed for display [%s] with error: %d",
+ mDisplay.getName().c_str(), result);
+ // Return fast here as we can't do much more - any rendering we do
+ // now will just be wrong.
+ return mGraphicBuffer;
+ }
+
+ ALOGW_IF(mGraphicBuffer != nullptr, "Clobbering a non-null pointer to a buffer [%p].",
+ mGraphicBuffer->getNativeBuffer()->handle);
+ mGraphicBuffer = GraphicBuffer::from(buffer);
+
+ // Block until the buffer is ready
+ // TODO(alecmouri): it's perhaps more appropriate to block renderengine so
+ // that the gl driver can block instead.
+ if (fd >= 0) {
+ sync_wait(fd, -1);
+ close(fd);
+ }
+
+ return mGraphicBuffer;
+}
+
+void RenderSurface::queueBuffer() {
+ auto& hwc = mCompositionEngine.getHwComposer();
+ const auto id = mDisplay.getId();
+
+ if (hwc.hasClientComposition(id) || hwc.hasFlipClientTargetRequest(id)) {
+ // hasFlipClientTargetRequest could return true even if we haven't
+ // dequeued a buffer before. Try dequeueing one if we don't have a
+ // buffer ready.
+ if (mGraphicBuffer == nullptr) {
+ ALOGI("Attempting to queue a client composited buffer without one "
+ "previously dequeued for display [%s]. Attempting to dequeue "
+ "a scratch buffer now",
+ mDisplay.getName().c_str());
+ // We shouldn't deadlock here, since mGraphicBuffer == nullptr only
+ // after a successful call to queueBuffer, or if dequeueBuffer has
+ // never been called.
+ dequeueBuffer();
+ }
+
+ if (mGraphicBuffer == nullptr) {
+ ALOGE("No buffer is ready for display [%s]", mDisplay.getName().c_str());
+ } else {
+ status_t result = mNativeWindow->queueBuffer(mNativeWindow.get(),
+ mGraphicBuffer->getNativeBuffer(),
+ dup(mBufferReady));
+ if (result != NO_ERROR) {
+ ALOGE("Error when queueing buffer for display [%s]: %d", mDisplay.getName().c_str(),
+ result);
+ // We risk blocking on dequeueBuffer if the primary display failed
+ // to queue up its buffer, so crash here.
+ if (!mDisplay.isVirtual()) {
+ LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", result);
+ } else {
+ mNativeWindow->cancelBuffer(mNativeWindow.get(),
+ mGraphicBuffer->getNativeBuffer(),
+ dup(mBufferReady));
+ }
+ }
+
+ mBufferReady.reset();
+ mGraphicBuffer = nullptr;
+ }
+ }
+
+ status_t result = mDisplaySurface->advanceFrame();
+ if (result != NO_ERROR) {
+ ALOGE("[%s] failed pushing new frame to HWC: %d", mDisplay.getName().c_str(), result);
+ }
+}
+
+void RenderSurface::onPresentDisplayCompleted() {
+ mDisplaySurface->onFrameCommitted();
+}
+
+void RenderSurface::setViewportAndProjection() {
+ auto& renderEngine = mCompositionEngine.getRenderEngine();
+ Rect sourceCrop = Rect(mSize);
+ renderEngine.setViewportAndProjection(mSize.width, mSize.height, sourceCrop,
+ ui::Transform::ROT_0);
+}
+
+void RenderSurface::finishBuffer() {
+ auto& renderEngine = mCompositionEngine.getRenderEngine();
+ mBufferReady = renderEngine.flush();
+ if (mBufferReady.get() < 0) {
+ renderEngine.finish();
+ }
+}
+
+void RenderSurface::flip() {
+ mPageFlipCount++;
+}
+
+void RenderSurface::dump(std::string& out) const {
+ using android::base::StringAppendF;
+
+ out.append(" Composition RenderSurface State:");
+
+ out.append("\n ");
+
+ dumpVal(out, "size", mSize);
+ StringAppendF(&out, "ANativeWindow=%p (format %d) ", mNativeWindow.get(),
+ ANativeWindow_getFormat(mNativeWindow.get()));
+ dumpVal(out, "flips", mPageFlipCount);
+ out.append("\n");
+
+ String8 surfaceDump;
+ mDisplaySurface->dumpAsString(surfaceDump);
+ out.append(surfaceDump);
+}
+
+std::uint32_t RenderSurface::getPageFlipCount() const {
+ return mPageFlipCount;
+}
+
+void RenderSurface::setPageFlipCountForTest(std::uint32_t count) {
+ mPageFlipCount = count;
+}
+
+void RenderSurface::setSizeForTest(const ui::Size& size) {
+ mSize = size;
+}
+
+sp<GraphicBuffer>& RenderSurface::mutableGraphicBufferForTest() {
+ return mGraphicBuffer;
+}
+
+base::unique_fd& RenderSurface::mutableBufferReadyForTest() {
+ return mBufferReady;
+}
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
new file mode 100644
index 0000000..d20fdda
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
@@ -0,0 +1,644 @@
+/*
+ * Copyright 2019 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 <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <compositionengine/impl/DisplayColorProfile.h>
+#include <compositionengine/mock/CompositionEngine.h>
+#include <gtest/gtest.h>
+
+namespace android::hardware::graphics::common::V1_1 {
+
+// Note: These operator overloads need to be defined in the same namespace as
+// the values they print.
+
+std::ostream& operator<<(std::ostream& os, const RenderIntent& value) {
+ return os << toString(value) << " (" << static_cast<std::underlying_type_t<Dataspace>>(value)
+ << ")";
+}
+
+} // namespace android::hardware::graphics::common::V1_1
+
+namespace android::hardware::graphics::common::V1_2 {
+
+// Note: These operator overloads need to be defined in the same namespace as
+// the values they print.
+
+std::ostream& operator<<(std::ostream& os, const Dataspace& value) {
+ return os << toString(value) << " (" << static_cast<std::underlying_type_t<Dataspace>>(value)
+ << ")";
+}
+
+std::ostream& operator<<(std::ostream& os, const ColorMode& value) {
+ return os << toString(value) << " (" << static_cast<std::underlying_type_t<Dataspace>>(value)
+ << ")";
+}
+
+} // namespace android::hardware::graphics::common::V1_2
+
+namespace android::compositionengine {
+namespace {
+
+using testing::_;
+using testing::Contains;
+using testing::IsEmpty;
+using testing::Ref;
+using testing::Return;
+using testing::ReturnRef;
+using testing::SizeIs;
+using testing::StrictMock;
+
+using ui::ColorMode;
+using ui::Dataspace;
+using ui::Hdr;
+using ui::RenderIntent;
+
+// This allows us to simulate a vendor-specified intent being used.
+constexpr RenderIntent VendorRenderIntent = static_cast<RenderIntent>(0x100);
+
+class DisplayColorProfileTest : public testing::Test {
+public:
+ ~DisplayColorProfileTest() override = default;
+
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+};
+
+class ProfileFactory {
+public:
+ impl::DisplayColorProfile build() const {
+ return impl::DisplayColorProfile{DisplayColorProfileCreationArgs{
+ mHasWideColorGamut,
+ HdrCapabilities(mSupportedHdrTypes, mMaxLuminance, mMaxAverageLuminance,
+ mMinLuminance),
+ mSupportedPerFrameMetadata,
+ mSupportedColorModes,
+ }};
+ }
+
+ ProfileFactory& setHasWideColorGamut(bool value) {
+ mHasWideColorGamut = value;
+ return *this;
+ }
+
+ ProfileFactory& setPerFrameMetadata(int32_t value) {
+ mSupportedPerFrameMetadata = value;
+ return *this;
+ }
+
+ ProfileFactory& addHdrType(Hdr value) {
+ mSupportedHdrTypes.emplace_back(value);
+ return *this;
+ }
+
+ ProfileFactory& addHdrTypes(std::initializer_list<Hdr> values) {
+ for (auto value : values) {
+ mSupportedHdrTypes.emplace_back(value);
+ }
+ return *this;
+ }
+
+ ProfileFactory& setMaxLuminance(float value) {
+ mMaxLuminance = value;
+ return *this;
+ }
+
+ ProfileFactory& setMaxAverageLuminance(float value) {
+ mMaxAverageLuminance = value;
+ return *this;
+ }
+
+ ProfileFactory& setMinLuminance(float value) {
+ mMinLuminance = value;
+ return *this;
+ }
+
+ ProfileFactory& addColorModeRenderIntent(ColorMode colorMode, RenderIntent renderIntent) {
+ mSupportedColorModes[colorMode].emplace_back(renderIntent);
+ return *this;
+ }
+
+ ProfileFactory& addColorModeRenderIntents(ColorMode colorMode,
+ std::initializer_list<RenderIntent> renderIntents) {
+ auto& profileedRenderIntents = mSupportedColorModes[colorMode];
+ for (auto renderIntent : renderIntents) {
+ profileedRenderIntents.emplace_back(renderIntent);
+ }
+ return *this;
+ }
+
+ static impl::DisplayColorProfile createProfileWithNoColorModeSupport() {
+ return ProfileFactory().build();
+ }
+
+ static impl::DisplayColorProfile createProfileWithBT2020ColorModeSupport() {
+ return ProfileFactory()
+ .setHasWideColorGamut(true)
+ .addHdrType(Hdr::HDR10)
+ .addColorModeRenderIntent(ColorMode::DISPLAY_BT2020, VendorRenderIntent)
+ .build();
+ }
+
+ static impl::DisplayColorProfile createProfileWithSRGBColorModeSupport() {
+ return ProfileFactory()
+ .setHasWideColorGamut(true)
+ .addHdrType(Hdr::HDR10)
+ .addColorModeRenderIntent(ColorMode::SRGB, VendorRenderIntent)
+ .build();
+ }
+
+ static impl::DisplayColorProfile createProfileWithBT2100PQSupport() {
+ return ProfileFactory()
+ .setHasWideColorGamut(true)
+ .addHdrType(Hdr::HLG)
+ .addColorModeRenderIntent(ColorMode::BT2100_PQ, VendorRenderIntent)
+ .build();
+ }
+
+private:
+ bool mHasWideColorGamut = false;
+ std::vector<Hdr> mSupportedHdrTypes;
+ float mMaxLuminance = -1.f;
+ float mMaxAverageLuminance = -1.f;
+ float mMinLuminance = -1.f;
+ int32_t mSupportedPerFrameMetadata = 0;
+ std::unordered_map<ColorMode, std::vector<RenderIntent>> mSupportedColorModes;
+};
+
+/* ------------------------------------------------------------------------
+ * RenderSurface Construction
+ */
+
+TEST_F(DisplayColorProfileTest, ctorSetsHasWideColorGamutFromInputArgs) {
+ {
+ auto profile = ProfileFactory().setHasWideColorGamut(false).build();
+
+ EXPECT_FALSE(profile.hasWideColorGamut());
+ }
+
+ {
+ auto profile = ProfileFactory().setHasWideColorGamut(true).build();
+
+ EXPECT_TRUE(profile.hasWideColorGamut());
+ }
+}
+
+TEST_F(DisplayColorProfileTest, ctorSetsSupportedPerFrameMetadataFromInputArgs) {
+ {
+ auto profile = ProfileFactory().setPerFrameMetadata(0).build();
+
+ EXPECT_EQ(0, profile.getSupportedPerFrameMetadata());
+ }
+
+ {
+ impl::DisplayColorProfile profile = ProfileFactory().setPerFrameMetadata(123).build();
+
+ EXPECT_EQ(123, profile.getSupportedPerFrameMetadata());
+ }
+}
+
+TEST_F(DisplayColorProfileTest, ctorDetectsSupportedHdrTypesFromInputArgs) {
+ {
+ // The constructor will set the internal state to not indicate any
+ // profile for HDR modes if none are profileed.
+ auto profile = ProfileFactory().build();
+
+ EXPECT_FALSE(profile.hasHDR10PlusSupport());
+ EXPECT_FALSE(profile.hasHDR10Support());
+ EXPECT_FALSE(profile.hasHLGSupport());
+ EXPECT_FALSE(profile.hasDolbyVisionSupport());
+ }
+
+ {
+ // The constructor will set the intenral state to indicate HDR10Plus
+ // profile if the input arguments indicate it is profileed.
+ auto profile = ProfileFactory().addHdrType(Hdr::HDR10_PLUS).build();
+
+ EXPECT_TRUE(profile.hasHDR10PlusSupport());
+ EXPECT_FALSE(profile.hasHDR10Support());
+ EXPECT_FALSE(profile.hasHLGSupport());
+ EXPECT_FALSE(profile.hasDolbyVisionSupport());
+ }
+
+ {
+ // The constructor will set the intenral state to indicate HDR10 profile
+ // if the input arguments indicate it is profileed.
+ auto profile = ProfileFactory().addHdrType(Hdr::HDR10).build();
+
+ EXPECT_FALSE(profile.hasHDR10PlusSupport());
+ EXPECT_TRUE(profile.hasHDR10Support());
+ EXPECT_FALSE(profile.hasHLGSupport());
+ EXPECT_FALSE(profile.hasDolbyVisionSupport());
+ }
+
+ {
+ // The constructor will set the intenral state to indicate HLG profile
+ // if the input arguments indicate it is profileed.
+ auto profile = ProfileFactory().addHdrType(Hdr::HLG).build();
+
+ EXPECT_FALSE(profile.hasHDR10PlusSupport());
+ EXPECT_FALSE(profile.hasHDR10Support());
+ EXPECT_TRUE(profile.hasHLGSupport());
+ EXPECT_FALSE(profile.hasDolbyVisionSupport());
+ }
+
+ {
+ // The constructor will set the intenral state to indicate Dolbyvision profile
+ // if the input arguments indicate it is profileed.
+ auto profile = ProfileFactory().addHdrType(Hdr::DOLBY_VISION).build();
+
+ EXPECT_FALSE(profile.hasHDR10Support());
+ EXPECT_FALSE(profile.hasHLGSupport());
+ EXPECT_TRUE(profile.hasDolbyVisionSupport());
+ }
+}
+
+TEST_F(DisplayColorProfileTest, ctorUsesOrDefaultsLuminanceValuesFromInputArgs) {
+ {
+ // The constructor will use a default value for each luminance setting
+ // that is negative.
+ auto profile = ProfileFactory()
+ .setMaxLuminance(-1.f)
+ .setMaxAverageLuminance(-1.f)
+ .setMinLuminance(-1.f)
+ .build();
+
+ EXPECT_EQ(DisplayColorProfile::sDefaultMaxLumiance,
+ profile.getHdrCapabilities().getDesiredMaxLuminance());
+ EXPECT_EQ(DisplayColorProfile::sDefaultMaxLumiance,
+ profile.getHdrCapabilities().getDesiredMaxAverageLuminance());
+ EXPECT_EQ(DisplayColorProfile::sDefaultMinLumiance,
+ profile.getHdrCapabilities().getDesiredMinLuminance());
+ }
+
+ {
+ // The constructor will otherwise take and use a positive value for each
+ // of the luminance settings.
+ auto profile = ProfileFactory()
+ .setMaxLuminance(1001.f)
+ .setMaxAverageLuminance(1002.f)
+ .setMinLuminance(1003.f)
+ .build();
+
+ EXPECT_EQ(1001.f, profile.getHdrCapabilities().getDesiredMaxLuminance());
+ EXPECT_EQ(1002.f, profile.getHdrCapabilities().getDesiredMaxAverageLuminance());
+ EXPECT_EQ(1003.f, profile.getHdrCapabilities().getDesiredMinLuminance());
+ }
+}
+
+TEST_F(DisplayColorProfileTest, ctorSignalsHdrSupportForAnyWideColorGamutDevice) {
+ {
+ // If the output does not profile wide color gamut, then no HDR modes
+ // will be profileed in the generated HDR capabilities.
+ auto profile = ProfileFactory().setHasWideColorGamut(false).build();
+
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), IsEmpty());
+ }
+
+ {
+ // If the HWC does not show profile for certain HDR modes, then the
+ // generated HDR capabilities will indicate profile anyway.
+ auto profile = ProfileFactory().setHasWideColorGamut(true).build();
+
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), SizeIs(2));
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HDR10));
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HLG));
+ }
+
+ {
+ // If the HWC profiles the HDR modes, then the generated capabilities
+ // still has one entry for each HDR type.
+ auto profile = ProfileFactory()
+ .setHasWideColorGamut(true)
+ .addHdrTypes({Hdr::HLG, Hdr::HDR10})
+ .build();
+
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), SizeIs(2));
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HDR10));
+ EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HLG));
+ }
+}
+
+/* ------------------------------------------------------------------------
+ * DisplayColorProfile::hasRenderIntent
+ */
+
+TEST_F(DisplayColorProfileTest, hasRenderIntentReturnsExpectedValueWhenOutputHasNoSupport) {
+ auto profile = ProfileFactory::createProfileWithNoColorModeSupport();
+
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(VendorRenderIntent));
+}
+
+TEST_F(DisplayColorProfileTest, hasRenderIntentReturnsExpectedValueWhenOutputHasBT2020upport) {
+ auto profile = ProfileFactory::createProfileWithBT2020ColorModeSupport();
+
+ EXPECT_TRUE(profile.hasRenderIntent(RenderIntent::COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(VendorRenderIntent));
+}
+
+TEST_F(DisplayColorProfileTest, hasRenderIntentReturnsExpectedValueWhenOutputHasSRGBSupport) {
+ auto profile = ProfileFactory::createProfileWithSRGBColorModeSupport();
+
+ EXPECT_TRUE(profile.hasRenderIntent(RenderIntent::COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_ENHANCE));
+ EXPECT_TRUE(profile.hasRenderIntent(VendorRenderIntent));
+}
+
+TEST_F(DisplayColorProfileTest, hasRenderIntentReturnsExpectedValueWhenOutputHasBTG2100PQSupport) {
+ auto profile = ProfileFactory::createProfileWithBT2100PQSupport();
+
+ EXPECT_TRUE(profile.hasRenderIntent(RenderIntent::COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_COLORIMETRIC));
+ EXPECT_FALSE(profile.hasRenderIntent(RenderIntent::TONE_MAP_ENHANCE));
+ EXPECT_FALSE(profile.hasRenderIntent(VendorRenderIntent));
+}
+
+/* ------------------------------------------------------------------------
+ * DisplayColorProfile::hasLegacyHdrSupport
+ */
+
+TEST_F(DisplayColorProfileTest, hasLegacyHdrSupport) {
+ {
+ auto profile = ProfileFactory::createProfileWithNoColorModeSupport();
+
+ EXPECT_FALSE(profile.hasLegacyHdrSupport(Dataspace::BT2020_PQ));
+ EXPECT_FALSE(profile.hasLegacyHdrSupport(Dataspace::BT2020_HLG));
+ }
+
+ {
+ auto profile = ProfileFactory::createProfileWithBT2020ColorModeSupport();
+
+ EXPECT_TRUE(profile.hasLegacyHdrSupport(Dataspace::BT2020_PQ));
+ EXPECT_FALSE(profile.hasLegacyHdrSupport(Dataspace::BT2020_HLG));
+ }
+
+ {
+ auto profile = ProfileFactory::createProfileWithSRGBColorModeSupport();
+
+ EXPECT_TRUE(profile.hasLegacyHdrSupport(Dataspace::BT2020_PQ));
+ EXPECT_FALSE(profile.hasLegacyHdrSupport(Dataspace::BT2020_HLG));
+ }
+
+ {
+ auto profile = ProfileFactory::createProfileWithBT2100PQSupport();
+
+ EXPECT_FALSE(profile.hasLegacyHdrSupport(Dataspace::BT2020_PQ));
+ EXPECT_TRUE(profile.hasLegacyHdrSupport(Dataspace::BT2020_HLG));
+ }
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::getBestColorMode()
+ */
+
+void checkGetBestColorMode(
+ DisplayColorProfile& profile,
+ const std::array<std::tuple<Dataspace, ColorMode, RenderIntent>, 25>& expected) {
+ using ArgsType = std::tuple<Dataspace, RenderIntent>;
+
+ // These are the combinations of dataspaces and render intents that could be
+ // passed to RenderSurface::getBestColorMode()
+ const std::array<std::tuple<Dataspace, RenderIntent>, 25> kArgs = {
+ /* clang-format off */
+
+ // Non-HDR combinations
+
+ /* 0 */ ArgsType{Dataspace::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 1 */ ArgsType{Dataspace::DISPLAY_BT2020, RenderIntent::ENHANCE},
+ /* 2 */ ArgsType{Dataspace::DISPLAY_BT2020, RenderIntent::TONE_MAP_COLORIMETRIC}, // Vendor explicit setting
+ /* 3 */ ArgsType{Dataspace::DISPLAY_BT2020, RenderIntent::TONE_MAP_ENHANCE}, // Vendor explicit setting
+ /* 4 */ ArgsType{Dataspace::DISPLAY_BT2020, VendorRenderIntent}, // Vendor explicit setting
+
+ /* 5 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::COLORIMETRIC},
+ /* 6 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::ENHANCE},
+ /* 7 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::TONE_MAP_COLORIMETRIC}, // Vendor explicit setting
+ /* 8 */ ArgsType{Dataspace::DISPLAY_P3, RenderIntent::TONE_MAP_ENHANCE}, // Vendor explicit setting
+ /* 9 */ ArgsType{Dataspace::DISPLAY_P3, VendorRenderIntent}, // Vendor explicit setting
+
+ /* 10 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::COLORIMETRIC},
+ /* 11 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::ENHANCE},
+ /* 12 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::TONE_MAP_COLORIMETRIC}, // Vendor explicit setting
+ /* 13 */ ArgsType{Dataspace::V0_SRGB, RenderIntent::TONE_MAP_ENHANCE}, // Vendor explicit setting
+ /* 14 */ ArgsType{Dataspace::V0_SRGB, VendorRenderIntent}, // Vendor explicit setting
+
+ // HDR combinations
+
+ /* 15 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::TONE_MAP_COLORIMETRIC},
+ /* 16 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::TONE_MAP_ENHANCE},
+ /* 17 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::COLORIMETRIC}, // Vendor explicit setting
+ /* 18 */ ArgsType{Dataspace::BT2020_PQ, RenderIntent::ENHANCE}, // Vendor explicit setting
+ /* 19 */ ArgsType{Dataspace::BT2020_PQ, VendorRenderIntent}, // Vendor explicit setting
+
+ /* 20 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::TONE_MAP_COLORIMETRIC},
+ /* 21 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::TONE_MAP_ENHANCE},
+ /* 22 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::COLORIMETRIC}, // Vendor explicit setting
+ /* 23 */ ArgsType{Dataspace::BT2020_HLG, RenderIntent::ENHANCE}, // Vendor explicit setting
+ /* 24 */ ArgsType{Dataspace::BT2020_HLG, VendorRenderIntent}, // Vendor explicit setting
+ /* clang-format on */
+ };
+
+ for (size_t i = 0; i < kArgs.size(); i++) {
+ std::tuple<Dataspace, ColorMode, RenderIntent> actual;
+ profile.getBestColorMode(std::get<0>(kArgs[i]), std::get<1>(kArgs[i]), &std::get<0>(actual),
+ &std::get<1>(actual), &std::get<2>(actual));
+
+ EXPECT_EQ(expected[i], actual) << " for index " << i;
+ }
+}
+
+TEST_F(DisplayColorProfileTest, getBestColorModeReturnsExpectedModesWhenOutputHasNoSupport) {
+ auto profile = ProfileFactory::createProfileWithNoColorModeSupport();
+
+ // Note: This table of expected values goes with the table of arguments
+ // used in checkGetBestColorMode.
+ using Result = std::tuple<Dataspace, ColorMode, RenderIntent>;
+ std::array<Result, 25> expectedResults = {
+ /* clang-format off */
+ /* 0 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 1 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 2 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 3 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 4 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 5 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 6 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 7 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 8 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 9 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 10 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 11 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 12 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 13 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 14 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 15 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 16 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 17 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 18 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 20 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 21 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 22 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 23 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 24 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* clang-format on */
+ };
+
+ checkGetBestColorMode(profile, expectedResults);
+}
+
+TEST_F(DisplayColorProfileTest, getBestColorModeReturnsExpectedModesWhenOutputHasBT2020Support) {
+ auto profile = ProfileFactory::createProfileWithBT2020ColorModeSupport();
+
+ // Note: This table of expected values goes with the table of arguments
+ // used in checkGetBestColorMode.
+ using Result = std::tuple<Dataspace, ColorMode, RenderIntent>;
+ std::array<Result, 25> expectedResults = {
+ /* clang-format off */
+ /* 0 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 1 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 2 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 3 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 4 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 5 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 6 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 7 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 8 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 9 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 10 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 11 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 12 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 13 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 14 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 15 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 16 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 17 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 18 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 20 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 21 */ Result{Dataspace::DISPLAY_BT2020, ColorMode::DISPLAY_BT2020, RenderIntent::COLORIMETRIC},
+ /* 22 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 23 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 24 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* clang-format on */
+ };
+
+ checkGetBestColorMode(profile, expectedResults);
+}
+
+TEST_F(DisplayColorProfileTest, getBestColorModeReturnsExpectedModesWhenOutputHasSRGBSupport) {
+ auto profile = ProfileFactory::createProfileWithSRGBColorModeSupport();
+
+ // Note: This table of expected values goes with the table of arguments
+ // used in checkGetBestColorMode.
+ using Result = std::tuple<Dataspace, ColorMode, RenderIntent>;
+ std::array<Result, 25> expectedResults = {
+ /* clang-format off */
+ /* 0 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 1 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 2 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 3 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 4 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, VendorRenderIntent},
+
+ /* 5 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 6 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 7 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 8 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 9 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, VendorRenderIntent},
+
+ /* 10 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 11 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 12 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 13 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 14 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, VendorRenderIntent},
+
+ /* 15 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 16 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 17 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 18 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 20 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 21 */ Result{Dataspace::V0_SRGB, ColorMode::SRGB, RenderIntent::COLORIMETRIC},
+ /* 22 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 23 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 24 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* clang-format on */
+ };
+
+ checkGetBestColorMode(profile, expectedResults);
+}
+
+TEST_F(DisplayColorProfileTest, getBestColorModeReturnsExpectedModesWhenOutputHasBT2100PQSupport) {
+ auto profile = ProfileFactory::createProfileWithBT2100PQSupport();
+
+ // Note: This table of expected values goes with the table of arguments
+ // used in checkGetBestColorMode.
+ using Result = std::tuple<Dataspace, ColorMode, RenderIntent>;
+ std::array<Result, 25> expectedResults = {
+ /* clang-format off */
+ /* 0 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 1 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 2 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 3 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 4 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 5 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 6 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 7 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 8 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 9 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 11 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 12 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 13 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 14 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 15 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
+ /* 16 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
+ /* 17 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 18 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 19 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+
+ /* 20 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
+ /* 21 */ Result{Dataspace::BT2020_PQ, ColorMode::BT2100_PQ, RenderIntent::COLORIMETRIC},
+ /* 22 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 23 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* 24 */ Result{Dataspace::UNKNOWN, ColorMode::NATIVE, RenderIntent::COLORIMETRIC},
+ /* clang-format on */
+ };
+
+ checkGetBestColorMode(profile, expectedResults);
+}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
new file mode 100644
index 0000000..8cb6936
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2019 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 <cmath>
+
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <compositionengine/DisplayCreationArgs.h>
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/Display.h>
+#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/RenderSurface.h>
+#include <gtest/gtest.h>
+#include <system/window.h>
+
+#include "MockHWComposer.h"
+
+namespace android::compositionengine {
+namespace {
+
+using testing::Return;
+using testing::ReturnRef;
+using testing::StrictMock;
+
+constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42};
+
+class DisplayTest : public testing::Test {
+public:
+ ~DisplayTest() override = default;
+
+ StrictMock<android::mock::HWComposer> mHwComposer;
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ impl::Display mDisplay{mCompositionEngine,
+ DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()};
+};
+
+/* ------------------------------------------------------------------------
+ * Basic construction
+ */
+
+TEST_F(DisplayTest, canInstantiateDisplay) {
+ {
+ constexpr DisplayId display1 = DisplayId{123u};
+ auto display =
+ impl::createDisplay(mCompositionEngine,
+ DisplayCreationArgsBuilder().setDisplayId(display1).build());
+ EXPECT_FALSE(display->isSecure());
+ EXPECT_FALSE(display->isVirtual());
+ EXPECT_EQ(display1, display->getId());
+ }
+
+ {
+ constexpr DisplayId display2 = DisplayId{546u};
+ auto display = impl::createDisplay(mCompositionEngine,
+ DisplayCreationArgsBuilder()
+ .setIsSecure(true)
+ .setDisplayId(display2)
+ .build());
+ EXPECT_TRUE(display->isSecure());
+ EXPECT_FALSE(display->isVirtual());
+ EXPECT_EQ(display2, display->getId());
+ }
+
+ {
+ constexpr DisplayId display3 = DisplayId{789u};
+ auto display = impl::createDisplay(mCompositionEngine,
+ DisplayCreationArgsBuilder()
+ .setIsVirtual(true)
+ .setDisplayId(display3)
+ .build());
+ EXPECT_FALSE(display->isSecure());
+ EXPECT_TRUE(display->isVirtual());
+ EXPECT_EQ(display3, display->getId());
+ }
+}
+
+/* ------------------------------------------------------------------------
+ * Display::disconnect()
+ */
+
+TEST_F(DisplayTest, disconnectDisconnectsDisplay) {
+ EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+
+ // The first call to disconnect will disconnect the display with the HWC and
+ // set mHwcId to -1.
+ EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(1);
+ mDisplay.disconnect();
+ EXPECT_FALSE(mDisplay.getId());
+
+ // Subsequent calls will do nothing,
+ EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(0);
+ mDisplay.disconnect();
+ EXPECT_FALSE(mDisplay.getId());
+}
+
+/* ------------------------------------------------------------------------
+ * Display::setColorTransform()
+ */
+
+TEST_F(DisplayTest, setColorTransformSetsTransform) {
+ // Identity matrix sets an identity state value
+ const mat4 identity;
+
+ EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+
+ EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, identity)).Times(1);
+
+ mDisplay.setColorTransform(identity);
+
+ EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mDisplay.getState().colorTransform);
+
+ // Non-identity matrix sets a non-identity state value
+ const mat4 nonIdentity = mat4() * 2;
+
+ EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, nonIdentity)).Times(1);
+
+ mDisplay.setColorTransform(nonIdentity);
+
+ EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mDisplay.getState().colorTransform);
+}
+
+/* ------------------------------------------------------------------------
+ * Display::setColorMode()
+ */
+
+TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) {
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ mDisplay.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+
+ EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+
+ // These values are expected to be the initial state.
+ ASSERT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode);
+ ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace);
+ ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
+
+ // Otherwise if the values are unchanged, nothing happens
+ mDisplay.setColorMode(ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN,
+ ui::RenderIntent::COLORIMETRIC);
+
+ EXPECT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace);
+ EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
+
+ // Otherwise if the values are different, updates happen
+ EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::SRGB)).Times(1);
+ EXPECT_CALL(mHwComposer,
+ setActiveColorMode(DEFAULT_DISPLAY_ID, ui::ColorMode::BT2100_PQ,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC))
+ .Times(1);
+
+ mDisplay.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+
+ EXPECT_EQ(ui::ColorMode::BT2100_PQ, mDisplay.getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::SRGB, mDisplay.getState().dataspace);
+ EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mDisplay.getState().renderIntent);
+}
+
+TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) {
+ impl::Display virtualDisplay{mCompositionEngine,
+ DisplayCreationArgs{false, true, DEFAULT_DISPLAY_ID}};
+
+ virtualDisplay.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+
+ EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay.getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay.getState().dataspace);
+ EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, virtualDisplay.getState().renderIntent);
+}
+
+/* ------------------------------------------------------------------------
+ * Display::createDisplayColorProfile()
+ */
+
+TEST_F(DisplayTest, createDisplayColorProfileSetsDisplayColorProfile) {
+ EXPECT_TRUE(mDisplay.getDisplayColorProfile() == nullptr);
+ mDisplay.createDisplayColorProfile(
+ DisplayColorProfileCreationArgs{false, HdrCapabilities(), 0,
+ DisplayColorProfileCreationArgs::HwcColorModes()});
+ EXPECT_TRUE(mDisplay.getDisplayColorProfile() != nullptr);
+}
+
+/* ------------------------------------------------------------------------
+ * Display::createRenderSurface()
+ */
+
+TEST_F(DisplayTest, createRenderSurfaceSetsRenderSurface) {
+ EXPECT_TRUE(mDisplay.getRenderSurface() == nullptr);
+ mDisplay.createRenderSurface(RenderSurfaceCreationArgs{640, 480, nullptr, nullptr});
+ EXPECT_TRUE(mDisplay.getRenderSurface() != nullptr);
+}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
new file mode 100644
index 0000000..f060cff
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2019 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 <cmath>
+
+#include <compositionengine/impl/Output.h>
+#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/DisplayColorProfile.h>
+#include <compositionengine/mock/RenderSurface.h>
+#include <gtest/gtest.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+#include "RegionMatcher.h"
+#include "TransformMatcher.h"
+
+namespace android::compositionengine {
+namespace {
+
+using testing::Return;
+using testing::ReturnRef;
+using testing::StrictMock;
+
+class OutputTest : public testing::Test {
+public:
+ OutputTest() {
+ mOutput.setDisplayColorProfileForTest(
+ std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
+ mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+ }
+ ~OutputTest() override = default;
+
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
+ mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
+ impl::Output mOutput{mCompositionEngine};
+};
+
+/* ------------------------------------------------------------------------
+ * Basic construction
+ */
+
+TEST_F(OutputTest, canInstantiateOutput) {
+ // The validation check checks each required component.
+ EXPECT_CALL(*mDisplayColorProfile, isValid()).WillOnce(Return(true));
+ EXPECT_CALL(*mRenderSurface, isValid()).WillOnce(Return(true));
+
+ EXPECT_TRUE(mOutput.isValid());
+
+ // If we take away the required components, it is no longer valid.
+ mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>());
+
+ EXPECT_CALL(*mDisplayColorProfile, isValid()).WillOnce(Return(true));
+
+ EXPECT_FALSE(mOutput.isValid());
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setCompositionEnabled()
+ */
+
+TEST_F(OutputTest, setCompositionEnabledDoesNothingIfAlreadyEnabled) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+ mOutput.editState().isEnabled = true;
+
+ mOutput.setCompositionEnabled(true);
+
+ EXPECT_TRUE(mOutput.getState().isEnabled);
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
+}
+
+TEST_F(OutputTest, setCompositionEnabledSetsEnabledAndDirtiesEntireOutput) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+ mOutput.editState().isEnabled = false;
+
+ mOutput.setCompositionEnabled(true);
+
+ EXPECT_TRUE(mOutput.getState().isEnabled);
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+}
+
+TEST_F(OutputTest, setCompositionEnabledSetsDisabledAndDirtiesEntireOutput) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+ mOutput.editState().isEnabled = true;
+
+ mOutput.setCompositionEnabled(false);
+
+ EXPECT_FALSE(mOutput.getState().isEnabled);
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setProjection()
+ */
+
+TEST_F(OutputTest, setProjectionTriviallyWorks) {
+ const ui::Transform transform{ui::Transform::ROT_180};
+ const int32_t orientation = 123;
+ const Rect frame{1, 2, 3, 4};
+ const Rect viewport{5, 6, 7, 8};
+ const Rect scissor{9, 10, 11, 12};
+ const bool needsFiltering = true;
+
+ mOutput.setProjection(transform, orientation, frame, viewport, scissor, needsFiltering);
+
+ EXPECT_THAT(mOutput.getState().transform, TransformEq(transform));
+ EXPECT_EQ(orientation, mOutput.getState().orientation);
+ EXPECT_EQ(frame, mOutput.getState().frame);
+ EXPECT_EQ(viewport, mOutput.getState().viewport);
+ EXPECT_EQ(scissor, mOutput.getState().scissor);
+ EXPECT_EQ(needsFiltering, mOutput.getState().needsFiltering);
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setBounds()
+ */
+
+TEST_F(OutputTest, setBoundsSetsSizeAndDirtiesEntireOutput) {
+ const ui::Size displaySize{100, 200};
+
+ EXPECT_CALL(*mRenderSurface, setDisplaySize(displaySize)).Times(1);
+ EXPECT_CALL(*mRenderSurface, getSize()).WillOnce(ReturnRef(displaySize));
+
+ mOutput.setBounds(displaySize);
+
+ EXPECT_EQ(Rect(displaySize), mOutput.getState().bounds);
+
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(Rect(displaySize))));
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setLayerStackFilter()
+ */
+
+TEST_F(OutputTest, setLayerStackFilterSetsFilterAndDirtiesEntireOutput) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+
+ const uint32_t layerStack = 123u;
+ mOutput.setLayerStackFilter(true, layerStack);
+
+ EXPECT_TRUE(mOutput.getState().singleLayerStack);
+ EXPECT_EQ(layerStack, mOutput.getState().singleLayerStackId);
+
+ EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(displaySize)));
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setColorTransform
+ */
+
+TEST_F(OutputTest, setColorTransformSetsTransform) {
+ // Identity matrix sets an identity state value
+ const mat4 identity;
+
+ mOutput.setColorTransform(identity);
+
+ EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mOutput.getState().colorTransform);
+
+ // Non-identity matrix sets a non-identity state value
+ const mat4 nonIdentity = mat4() * 2;
+
+ mOutput.setColorTransform(nonIdentity);
+
+ EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform);
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setColorMode
+ */
+
+TEST_F(OutputTest, setColorModeSetsModeUnlessNoChange) {
+ EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::SRGB)).Times(1);
+
+ mOutput.setColorMode(ui::ColorMode::BT2100_PQ, ui::Dataspace::SRGB,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+
+ EXPECT_EQ(ui::ColorMode::BT2100_PQ, mOutput.getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::SRGB, mOutput.getState().dataspace);
+ EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mOutput.getState().renderIntent);
+}
+
+/* ------------------------------------------------------------------------
+ * Output::setRenderSurface()
+ */
+
+TEST_F(OutputTest, setRenderSurfaceResetsBounds) {
+ const ui::Size newDisplaySize{640, 480};
+
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ EXPECT_CALL(*renderSurface, getSize()).WillOnce(ReturnRef(newDisplaySize));
+
+ mOutput.setRenderSurface(std::unique_ptr<RenderSurface>(renderSurface));
+
+ EXPECT_EQ(Rect(newDisplaySize), mOutput.getState().bounds);
+}
+
+/* ------------------------------------------------------------------------
+ * Output::getPhysicalSpaceDirtyRegion()
+ */
+
+TEST_F(OutputTest, getPhysicalSpaceDirtyRegionWithRepaintEverythingTrue) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+ mOutput.editState().dirtyRegion.set(50, 300);
+
+ {
+ Region result = mOutput.getPhysicalSpaceDirtyRegion(true);
+
+ EXPECT_THAT(result, RegionEq(Region(displaySize)));
+ }
+
+ // For repaint everything == true, the returned value does not depend on the display
+ // rotation.
+ mOutput.editState().transform.set(ui::Transform::ROT_90, 0, 0);
+
+ {
+ Region result = mOutput.getPhysicalSpaceDirtyRegion(true);
+
+ EXPECT_THAT(result, RegionEq(Region(displaySize)));
+ }
+}
+
+TEST_F(OutputTest, getPhysicalSpaceDirtyRegionWithRepaintEverythingFalse) {
+ const Rect displaySize{100, 200};
+ mOutput.editState().bounds = displaySize;
+ mOutput.editState().dirtyRegion.set(50, 300);
+
+ {
+ Region result = mOutput.getPhysicalSpaceDirtyRegion(false);
+
+ // The dirtyRegion should be clipped to the display bounds.
+ EXPECT_THAT(result, RegionEq(Region(Rect(50, 200))));
+ }
+
+ mOutput.editState().transform.set(ui::Transform::ROT_90, displaySize.getWidth(),
+ displaySize.getHeight());
+
+ {
+ Region result = mOutput.getPhysicalSpaceDirtyRegion(false);
+
+ // The dirtyRegion should be rotated and clipped to the display bounds.
+ EXPECT_THAT(result, RegionEq(Region(Rect(100, 50))));
+ }
+}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/RegionMatcher.h b/services/surfaceflinger/CompositionEngine/tests/RegionMatcher.h
new file mode 100644
index 0000000..5a4efa9
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/RegionMatcher.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 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 <gmock/gmock.h>
+
+namespace {
+
+// Checks for a region match
+MATCHER_P(RegionEq, expected, "") {
+ std::string buf;
+ buf.append("Regions are not equal\n");
+ expected.dump(buf, "expected region");
+ arg.dump(buf, "actual region");
+ *result_listener << buf;
+
+ size_t expectedRectCount = 0;
+ android::Rect const* expectedRects = expected.getArray(&expectedRectCount);
+ size_t actualRectCount = 0;
+ android::Rect const* actualRects = arg.getArray(&actualRectCount);
+
+ if (expectedRectCount != actualRectCount) return false;
+ for (size_t i = 0; i < expectedRectCount; i++) {
+ if (expectedRects[i] != actualRects[i]) return false;
+ }
+ return true;
+}
+
+} // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
new file mode 100644
index 0000000..13cc663
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -0,0 +1,504 @@
+/*
+ * Copyright 2019 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 <cstdarg>
+#include <cstdint>
+
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/RenderSurface.h>
+#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/Display.h>
+#include <compositionengine/mock/DisplaySurface.h>
+#include <gtest/gtest.h>
+#include <renderengine/mock/RenderEngine.h>
+#include <system/window.h>
+#include <ui/ANativeObjectBase.h>
+
+#include "MockHWComposer.h"
+
+namespace android::compositionengine {
+namespace {
+
+/* ------------------------------------------------------------------------
+ * MockNativeWindow
+ *
+ * An intentionally simplified Mock which implements a minimal subset of the full
+ * ANativeWindow interface.
+ */
+
+class MockNativeWindow : public ANativeObjectBase<ANativeWindow, MockNativeWindow, RefBase> {
+public:
+ MockNativeWindow() {
+ ANativeWindow::setSwapInterval = &forwardSetSwapInterval;
+ ANativeWindow::dequeueBuffer = &forwardDequeueBuffer;
+ ANativeWindow::cancelBuffer = &forwardCancelBuffer;
+ ANativeWindow::queueBuffer = &forwardQueueBuffer;
+ ANativeWindow::query = &forwardQuery;
+ ANativeWindow::perform = &forwardPerform;
+
+ ANativeWindow::dequeueBuffer_DEPRECATED = &forwardDequeueBufferDeprecated;
+ ANativeWindow::cancelBuffer_DEPRECATED = &forwardCancelBufferDeprecated;
+ ANativeWindow::lockBuffer_DEPRECATED = &forwardLockBufferDeprecated;
+ ANativeWindow::queueBuffer_DEPRECATED = &forwardQueueBufferDeprecated;
+ }
+
+ MOCK_METHOD1(setSwapInterval, int(int));
+ MOCK_METHOD2(dequeueBuffer, int(struct ANativeWindowBuffer**, int*));
+ MOCK_METHOD2(cancelBuffer, int(struct ANativeWindowBuffer*, int));
+ MOCK_METHOD2(queueBuffer, int(struct ANativeWindowBuffer*, int));
+ MOCK_CONST_METHOD2(query, int(int, int*));
+ MOCK_METHOD1(connect, int(int));
+ MOCK_METHOD1(lockBuffer_DEPRECATED, int(struct ANativeWindowBuffer*));
+ MOCK_METHOD1(setBuffersFormat, int(PixelFormat));
+ MOCK_METHOD1(setBuffersDataSpace, int(ui::Dataspace));
+ MOCK_METHOD1(setUsage, int(uint64_t));
+
+ static void unexpectedCall(...) { LOG_ALWAYS_FATAL("Unexpected ANativeWindow API call"); }
+
+ static int forwardSetSwapInterval(ANativeWindow* window, int interval) {
+ return getSelf(window)->setSwapInterval(interval);
+ }
+
+ static int forwardDequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
+ int* fenceFd) {
+ return getSelf(window)->dequeueBuffer(buffer, fenceFd);
+ }
+
+ static int forwardCancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
+ int fenceFd) {
+ return getSelf(window)->cancelBuffer(buffer, fenceFd);
+ }
+
+ static int forwardQueueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) {
+ return getSelf(window)->queueBuffer(buffer, fenceFd);
+ }
+
+ static int forwardQuery(const ANativeWindow* window, int what, int* value) {
+ return getSelf(window)->query(what, value);
+ }
+
+ static int forwardPerform(ANativeWindow* window, int operation, ...) {
+ va_list args;
+ va_start(args, operation);
+ int result = NO_ERROR;
+ switch (operation) {
+ case NATIVE_WINDOW_API_CONNECT: {
+ int api = va_arg(args, int);
+ result = getSelf(window)->connect(api);
+ break;
+ }
+ case NATIVE_WINDOW_SET_BUFFERS_FORMAT: {
+ PixelFormat format = va_arg(args, PixelFormat);
+ result = getSelf(window)->setBuffersFormat(format);
+ break;
+ }
+ case NATIVE_WINDOW_SET_BUFFERS_DATASPACE: {
+ ui::Dataspace dataspace = static_cast<ui::Dataspace>(va_arg(args, int));
+ result = getSelf(window)->setBuffersDataSpace(dataspace);
+ break;
+ }
+ case NATIVE_WINDOW_SET_USAGE: {
+ // Note: Intentionally widens usage from 32 to 64 bits so we
+ // just have one implementation.
+ uint64_t usage = va_arg(args, uint32_t);
+ result = getSelf(window)->setUsage(usage);
+ break;
+ }
+ case NATIVE_WINDOW_SET_USAGE64: {
+ uint64_t usage = va_arg(args, uint64_t);
+ result = getSelf(window)->setUsage(usage);
+ break;
+ }
+ default:
+ LOG_ALWAYS_FATAL("Unexpected operation %d", operation);
+ break;
+ }
+
+ va_end(args);
+ return result;
+ }
+
+ static int forwardDequeueBufferDeprecated(ANativeWindow* window, ANativeWindowBuffer** buffer) {
+ int ignoredFenceFd = -1;
+ return getSelf(window)->dequeueBuffer(buffer, &ignoredFenceFd);
+ }
+
+ static int forwardCancelBufferDeprecated(ANativeWindow* window, ANativeWindowBuffer* buffer) {
+ return getSelf(window)->cancelBuffer(buffer, -1);
+ }
+
+ static int forwardLockBufferDeprecated(ANativeWindow* window, ANativeWindowBuffer* buffer) {
+ return getSelf(window)->lockBuffer_DEPRECATED(buffer);
+ }
+
+ static int forwardQueueBufferDeprecated(ANativeWindow* window, ANativeWindowBuffer* buffer) {
+ return getSelf(window)->queueBuffer(buffer, -1);
+ }
+};
+
+/* ------------------------------------------------------------------------
+ * RenderSurfaceTest
+ */
+
+constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920;
+constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080;
+constexpr std::optional<DisplayId> DEFAULT_DISPLAY_ID = std::make_optional(DisplayId{123u});
+const std::string DEFAULT_DISPLAY_NAME = "Mock Display";
+
+using testing::_;
+using testing::ByMove;
+using testing::DoAll;
+using testing::Ref;
+using testing::Return;
+using testing::ReturnRef;
+using testing::SetArgPointee;
+using testing::StrictMock;
+
+class RenderSurfaceTest : public testing::Test {
+public:
+ RenderSurfaceTest() {
+ EXPECT_CALL(mDisplay, getId()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_ID));
+ EXPECT_CALL(mDisplay, getName()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_NAME));
+ EXPECT_CALL(mCompositionEngine, getHwComposer).WillRepeatedly(ReturnRef(mHwComposer));
+ EXPECT_CALL(mCompositionEngine, getRenderEngine).WillRepeatedly(ReturnRef(mRenderEngine));
+ }
+ ~RenderSurfaceTest() override = default;
+
+ StrictMock<android::mock::HWComposer> mHwComposer;
+ StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ StrictMock<mock::Display> mDisplay;
+ sp<MockNativeWindow> mNativeWindow = new StrictMock<MockNativeWindow>();
+ sp<mock::DisplaySurface> mDisplaySurface = new StrictMock<mock::DisplaySurface>();
+ impl::RenderSurface mSurface{mCompositionEngine, mDisplay,
+ RenderSurfaceCreationArgs{DEFAULT_DISPLAY_WIDTH,
+ DEFAULT_DISPLAY_HEIGHT, mNativeWindow,
+ mDisplaySurface}};
+};
+
+/* ------------------------------------------------------------------------
+ * Basic construction
+ */
+
+TEST_F(RenderSurfaceTest, canInstantiate) {
+ EXPECT_TRUE(mSurface.isValid());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::initialize()
+ */
+
+TEST_F(RenderSurfaceTest, initializeConfiguresNativeWindow) {
+ EXPECT_CALL(*mNativeWindow, connect(NATIVE_WINDOW_API_EGL)).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mNativeWindow, setBuffersFormat(HAL_PIXEL_FORMAT_RGBA_8888))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER)).WillOnce(Return(NO_ERROR));
+
+ mSurface.initialize();
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::getSize()
+ */
+
+TEST_F(RenderSurfaceTest, sizeReturnsConstructedSize) {
+ const ui::Size expected{DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT};
+
+ EXPECT_EQ(expected, mSurface.getSize());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::getClientTargetAcquireFence()
+ */
+
+TEST_F(RenderSurfaceTest, getClientTargetAcquireFenceForwardsCall) {
+ sp<Fence> fence = new Fence();
+
+ EXPECT_CALL(*mDisplaySurface, getClientTargetAcquireFence()).WillOnce(ReturnRef(fence));
+
+ EXPECT_EQ(fence.get(), mSurface.getClientTargetAcquireFence().get());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::setDisplaySize()
+ */
+
+TEST_F(RenderSurfaceTest, setDisplaySizeAppliesChange) {
+ EXPECT_CALL(*mDisplaySurface, resizeBuffers(640, 480)).Times(1);
+
+ mSurface.setDisplaySize(ui::Size(640, 480));
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::setBufferDataspace()
+ */
+
+TEST_F(RenderSurfaceTest, setBufferDataspaceAppliesChange) {
+ EXPECT_CALL(*mNativeWindow, setBuffersDataSpace(ui::Dataspace::DISPLAY_P3))
+ .WillOnce(Return(NO_ERROR));
+
+ mSurface.setBufferDataspace(ui::Dataspace::DISPLAY_P3);
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::setProtected()
+ */
+
+TEST_F(RenderSurfaceTest, setProtectedTrueEnablesProtection) {
+ EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_PROTECTED))
+ .WillOnce(Return(NO_ERROR));
+
+ mSurface.setProtected(true);
+}
+
+TEST_F(RenderSurfaceTest, setProtectedFalseDisablesProtection) {
+ EXPECT_CALL(*mNativeWindow, setUsage(GRALLOC_USAGE_HW_RENDER)).WillOnce(Return(NO_ERROR));
+
+ mSurface.setProtected(false);
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::beginFrame()
+ */
+
+TEST_F(RenderSurfaceTest, beginFrameAppliesChange) {
+ EXPECT_CALL(*mDisplaySurface, beginFrame(true)).WillOnce(Return(NO_ERROR));
+
+ EXPECT_EQ(NO_ERROR, mSurface.beginFrame(true));
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::prepareFrame()
+ */
+
+TEST_F(RenderSurfaceTest, prepareFrameTakesEarlyOutOnHwcError) {
+ std::vector<CompositionInfo> data;
+
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data)))
+ .WillOnce(Return(INVALID_OPERATION));
+
+ EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame(data));
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameHandlesMixedComposition) {
+ std::vector<CompositionInfo> data;
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+
+ EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_MIXED))
+ .WillOnce(Return(INVALID_OPERATION));
+
+ EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame(data));
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyGlesComposition) {
+ std::vector<CompositionInfo> data;
+
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+
+ EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
+ .WillOnce(Return(NO_ERROR));
+
+ EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyHwcComposition) {
+ std::vector<CompositionInfo> data;
+
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+
+ EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
+ .WillOnce(Return(NO_ERROR));
+
+ EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameHandlesNoComposition) {
+ std::vector<CompositionInfo> data;
+
+ EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+
+ EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
+ .WillOnce(Return(NO_ERROR));
+
+ EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::dequeueBuffer()
+ */
+
+TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+
+ EXPECT_CALL(*mNativeWindow, dequeueBuffer(_, _))
+ .WillOnce(
+ DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
+
+ EXPECT_EQ(buffer.get(), mSurface.dequeueBuffer().get());
+
+ EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::queueBuffer()
+ */
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ mSurface.mutableGraphicBufferForTest() = buffer;
+
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID))
+ .WillOnce(Return(false));
+ EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+ mSurface.queueBuffer();
+
+ EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
+}
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ mSurface.mutableGraphicBufferForTest() = buffer;
+
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+ mSurface.queueBuffer();
+
+ EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+}
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ mSurface.mutableGraphicBufferForTest() = buffer;
+
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+ mSurface.queueBuffer();
+
+ EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+}
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(*mNativeWindow, dequeueBuffer(_, _))
+ .WillOnce(
+ DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
+ EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+ mSurface.queueBuffer();
+
+ EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+}
+
+TEST_F(RenderSurfaceTest, queueBufferHandlesNativeWindowQueueBufferFailureOnVirtualDisplay) {
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ mSurface.mutableGraphicBufferForTest() = buffer;
+
+ EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
+ .WillOnce(Return(INVALID_OPERATION));
+ EXPECT_CALL(mDisplay, isVirtual()).WillOnce(Return(true));
+ EXPECT_CALL(*mNativeWindow, cancelBuffer(buffer->getNativeBuffer(), -1))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
+
+ mSurface.queueBuffer();
+
+ EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::onPresentDisplayCompleted()
+ */
+
+TEST_F(RenderSurfaceTest, onPresentDisplayCompletedForwardsSignal) {
+ EXPECT_CALL(*mDisplaySurface, onFrameCommitted()).Times(1);
+
+ mSurface.onPresentDisplayCompleted();
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::finishBuffer()
+ */
+
+TEST_F(RenderSurfaceTest, finishBufferJustFlushesRenderEngine) {
+ int fd = dup(1);
+
+ EXPECT_CALL(mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd(fd))));
+
+ mSurface.finishBuffer();
+
+ EXPECT_EQ(fd, mSurface.mutableBufferReadyForTest().release());
+}
+
+TEST_F(RenderSurfaceTest, finishBufferFlushesAndFinishesRenderEngine) {
+ EXPECT_CALL(mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd(-2))));
+ EXPECT_CALL(mRenderEngine, finish()).Times(1);
+
+ mSurface.finishBuffer();
+
+ EXPECT_EQ(-2, mSurface.mutableBufferReadyForTest().release());
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::setViewportAndProjection()
+ */
+
+TEST_F(RenderSurfaceTest, setViewportAndProjectionAppliesChang) {
+ mSurface.setSizeForTest(ui::Size(100, 200));
+
+ EXPECT_CALL(mRenderEngine,
+ setViewportAndProjection(100, 200, Rect(100, 200), ui::Transform::ROT_0))
+ .Times(1);
+
+ mSurface.setViewportAndProjection();
+}
+
+/* ------------------------------------------------------------------------
+ * RenderSurface::flip()
+ */
+
+TEST_F(RenderSurfaceTest, flipForwardsSignal) {
+ mSurface.setPageFlipCountForTest(500);
+
+ mSurface.flip();
+
+ EXPECT_EQ(501, mSurface.getPageFlipCount());
+}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/TransformMatcher.h b/services/surfaceflinger/CompositionEngine/tests/TransformMatcher.h
new file mode 100644
index 0000000..ea07bed
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/TransformMatcher.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 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 <string>
+
+#include <gmock/gmock.h>
+
+namespace {
+
+// Check for a transform match
+MATCHER_P(TransformEq, expected, "") {
+ std::string buf;
+ buf.append("Transforms are not equal\n");
+ expected.dump(buf, "expected transform");
+ arg.dump(buf, "actual transform");
+ *result_listener << buf;
+
+ const float TOLERANCE = 1e-3f;
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ if (std::fabs(expected[i][j] - arg[i][j]) > TOLERANCE) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+} // namespace
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index e7b7fbe..54111de 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -18,47 +18,28 @@
#undef LOG_TAG
#define LOG_TAG "DisplayDevice"
-#include "DisplayDevice.h"
-
-#include <array>
-#include <unordered_set>
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-
#include <android-base/stringprintf.h>
-#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <compositionengine/DisplayCreationArgs.h>
+#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/OutputCompositionState.h>
#include <configstore/Utils.h>
-#include <cutils/properties.h>
-#include <gui/Surface.h>
-#include <hardware/gralloc.h>
-#include <renderengine/RenderEngine.h>
-#include <sync/sync.h>
+#include <log/log.h>
#include <system/window.h>
-#include <ui/DebugUtils.h>
-#include <ui/DisplayInfo.h>
-#include <ui/PixelFormat.h>
-#include <utils/Log.h>
-#include <utils/RefBase.h>
+#include <ui/GraphicTypes.h>
-#include "DisplayHardware/DisplaySurface.h"
-#include "DisplayHardware/HWComposer.h"
-#include "DisplayHardware/HWC2.h"
-#include "SurfaceFlinger.h"
+#include "DisplayDevice.h"
#include "Layer.h"
+#include "SurfaceFlinger.h"
namespace android {
-// retrieve triple buffer setting from configstore
-using namespace android::hardware::configstore;
-using namespace android::hardware::configstore::V1_0;
using android::base::StringAppendF;
-using android::ui::ColorMode;
-using android::ui::Dataspace;
-using android::ui::Hdr;
-using android::ui::RenderIntent;
/*
* Initialize the display to the specified values.
@@ -67,413 +48,72 @@
uint32_t DisplayDevice::sPrimaryDisplayOrientation = 0;
-namespace {
-
-// ordered list of known SDR color modes
-const std::array<ColorMode, 3> sSdrColorModes = {
- ColorMode::DISPLAY_BT2020,
- ColorMode::DISPLAY_P3,
- ColorMode::SRGB,
-};
-
-// ordered list of known HDR color modes
-const std::array<ColorMode, 2> sHdrColorModes = {
- ColorMode::BT2100_PQ,
- ColorMode::BT2100_HLG,
-};
-
-// ordered list of known SDR render intents
-const std::array<RenderIntent, 2> sSdrRenderIntents = {
- RenderIntent::ENHANCE,
- RenderIntent::COLORIMETRIC,
-};
-
-// ordered list of known HDR render intents
-const std::array<RenderIntent, 2> sHdrRenderIntents = {
- RenderIntent::TONE_MAP_ENHANCE,
- RenderIntent::TONE_MAP_COLORIMETRIC,
-};
-
-// map known color mode to dataspace
-Dataspace colorModeToDataspace(ColorMode mode) {
- switch (mode) {
- case ColorMode::SRGB:
- return Dataspace::V0_SRGB;
- case ColorMode::DISPLAY_P3:
- return Dataspace::DISPLAY_P3;
- case ColorMode::DISPLAY_BT2020:
- return Dataspace::DISPLAY_BT2020;
- case ColorMode::BT2100_HLG:
- return Dataspace::BT2020_HLG;
- case ColorMode::BT2100_PQ:
- return Dataspace::BT2020_PQ;
- default:
- return Dataspace::UNKNOWN;
- }
-}
-
-// Return a list of candidate color modes.
-std::vector<ColorMode> getColorModeCandidates(ColorMode mode) {
- std::vector<ColorMode> candidates;
-
- // add mode itself
- candidates.push_back(mode);
-
- // check if mode is HDR
- bool isHdr = false;
- for (auto hdrMode : sHdrColorModes) {
- if (hdrMode == mode) {
- isHdr = true;
- break;
- }
- }
-
- // add other HDR candidates when mode is HDR
- if (isHdr) {
- for (auto hdrMode : sHdrColorModes) {
- if (hdrMode != mode) {
- candidates.push_back(hdrMode);
- }
- }
- }
-
- // add other SDR candidates
- for (auto sdrMode : sSdrColorModes) {
- if (sdrMode != mode) {
- candidates.push_back(sdrMode);
- }
- }
-
- return candidates;
-}
-
-// Return a list of candidate render intents.
-std::vector<RenderIntent> getRenderIntentCandidates(RenderIntent intent) {
- std::vector<RenderIntent> candidates;
-
- // add intent itself
- candidates.push_back(intent);
-
- // check if intent is HDR
- bool isHdr = false;
- for (auto hdrIntent : sHdrRenderIntents) {
- if (hdrIntent == intent) {
- isHdr = true;
- break;
- }
- }
-
- if (isHdr) {
- // add other HDR candidates when intent is HDR
- for (auto hdrIntent : sHdrRenderIntents) {
- if (hdrIntent != intent) {
- candidates.push_back(hdrIntent);
- }
- }
- } else {
- // add other SDR candidates when intent is SDR
- for (auto sdrIntent : sSdrRenderIntents) {
- if (sdrIntent != intent) {
- candidates.push_back(sdrIntent);
- }
- }
- }
-
- return candidates;
-}
-
-// Return the best color mode supported by HWC.
-ColorMode getHwcColorMode(
- const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes,
- ColorMode mode) {
- std::vector<ColorMode> candidates = getColorModeCandidates(mode);
- for (auto candidate : candidates) {
- auto iter = hwcColorModes.find(candidate);
- if (iter != hwcColorModes.end()) {
- return candidate;
- }
- }
-
- return ColorMode::NATIVE;
-}
-
-// Return the best render intent supported by HWC.
-RenderIntent getHwcRenderIntent(const std::vector<RenderIntent>& hwcIntents, RenderIntent intent) {
- std::vector<RenderIntent> candidates = getRenderIntentCandidates(intent);
- for (auto candidate : candidates) {
- for (auto hwcIntent : hwcIntents) {
- if (candidate == hwcIntent) {
- return candidate;
- }
- }
- }
-
- return RenderIntent::COLORIMETRIC;
-}
-
-} // anonymous namespace
-
DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger,
const wp<IBinder>& displayToken,
const std::optional<DisplayId>& displayId)
: flinger(flinger), displayToken(displayToken), displayId(displayId) {}
DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args)
- : lastCompositionHadVisibleLayers(false),
- mFlinger(args.flinger),
+ : mFlinger(args.flinger),
mDisplayToken(args.displayToken),
mSequenceId(args.sequenceId),
- mId(args.displayId),
- mNativeWindow(args.nativeWindow),
- mGraphicBuffer(nullptr),
- mDisplaySurface(args.displaySurface),
mDisplayInstallOrientation(args.displayInstallOrientation),
- mPageFlipCount(0),
+ mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay(
+ compositionengine::DisplayCreationArgs{args.isSecure, args.isVirtual,
+ args.displayId})},
mIsVirtual(args.isVirtual),
- mIsSecure(args.isSecure),
- mLayerStack(NO_LAYER_STACK),
mOrientation(),
- mViewport(Rect::INVALID_RECT),
- mFrame(Rect::INVALID_RECT),
- mPowerMode(args.initialPowerMode),
mActiveConfig(0),
- mColorTransform(HAL_COLOR_TRANSFORM_IDENTITY),
- mHasWideColorGamut(args.hasWideColorGamut),
- mHasHdr10Plus(false),
- mHasHdr10(false),
- mHasHLG(false),
- mHasDolbyVision(false),
- mSupportedPerFrameMetadata(args.supportedPerFrameMetadata),
mIsPrimary(args.isPrimary) {
- populateColorModes(args.hwcColorModes);
+ mCompositionDisplay->createRenderSurface(
+ compositionengine::RenderSurfaceCreationArgs{ANativeWindow_getWidth(
+ args.nativeWindow.get()),
+ ANativeWindow_getHeight(
+ args.nativeWindow.get()),
+ args.nativeWindow, args.displaySurface});
- ALOGE_IF(!mNativeWindow, "No native window was set for display");
- ALOGE_IF(!mDisplaySurface, "No display surface was set for display");
+ mCompositionDisplay->createDisplayColorProfile(
+ compositionengine::DisplayColorProfileCreationArgs{args.hasWideColorGamut,
+ std::move(args.hdrCapabilities),
+ args.supportedPerFrameMetadata,
+ args.hwcColorModes});
- std::vector<Hdr> types = args.hdrCapabilities.getSupportedHdrTypes();
- for (Hdr hdrType : types) {
- switch (hdrType) {
- case Hdr::HDR10_PLUS:
- mHasHdr10Plus = true;
- break;
- case Hdr::HDR10:
- mHasHdr10 = true;
- break;
- case Hdr::HLG:
- mHasHLG = true;
- break;
- case Hdr::DOLBY_VISION:
- mHasDolbyVision = true;
- break;
- default:
- ALOGE("UNKNOWN HDR capability: %d", static_cast<int32_t>(hdrType));
- }
+ if (!mCompositionDisplay->isValid()) {
+ ALOGE("Composition Display did not validate!");
}
- float minLuminance = args.hdrCapabilities.getDesiredMinLuminance();
- float maxLuminance = args.hdrCapabilities.getDesiredMaxLuminance();
- float maxAverageLuminance = args.hdrCapabilities.getDesiredMaxAverageLuminance();
+ mCompositionDisplay->getRenderSurface()->initialize();
- minLuminance = minLuminance <= 0.0 ? sDefaultMinLumiance : minLuminance;
- maxLuminance = maxLuminance <= 0.0 ? sDefaultMaxLumiance : maxLuminance;
- maxAverageLuminance = maxAverageLuminance <= 0.0 ? sDefaultMaxLumiance : maxAverageLuminance;
- if (this->hasWideColorGamut()) {
- // insert HDR10/HLG as we will force client composition for HDR10/HLG
- // layers
- if (!hasHDR10Support()) {
- types.push_back(Hdr::HDR10);
- }
-
- if (!hasHLGSupport()) {
- types.push_back(Hdr::HLG);
- }
- }
- mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
-
- ANativeWindow* const window = mNativeWindow.get();
-
- int status = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
- ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status);
- status = native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
- ALOGE_IF(status != NO_ERROR, "Unable to set BQ format to RGBA888: %d", status);
- status = native_window_set_usage(window, GRALLOC_USAGE_HW_RENDER);
- ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for GPU rendering: %d", status);
-
- mDisplayWidth = ANativeWindow_getWidth(window);
- mDisplayHeight = ANativeWindow_getHeight(window);
+ setPowerMode(args.initialPowerMode);
// initialize the display orientation transform.
- setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
+ setProjection(DisplayState::eOrientationDefault, Rect::INVALID_RECT, Rect::INVALID_RECT);
}
DisplayDevice::~DisplayDevice() = default;
-void DisplayDevice::disconnect(HWComposer& hwc) {
- if (mId) {
- hwc.disconnectDisplay(*mId);
- mId.reset();
- }
+void DisplayDevice::disconnect() {
+ mCompositionDisplay->disconnect();
}
int DisplayDevice::getWidth() const {
- return mDisplayWidth;
+ return mCompositionDisplay->getState().bounds.getWidth();
}
int DisplayDevice::getHeight() const {
- return mDisplayHeight;
+ return mCompositionDisplay->getState().bounds.getHeight();
}
void DisplayDevice::setDisplayName(const std::string& displayName) {
if (!displayName.empty()) {
// never override the name with an empty name
mDisplayName = displayName;
+ mCompositionDisplay->setName(displayName);
}
}
uint32_t DisplayDevice::getPageFlipCount() const {
- return mPageFlipCount;
-}
-
-void DisplayDevice::flip() const
-{
- mPageFlipCount++;
-}
-
-status_t DisplayDevice::beginFrame(bool mustRecompose) const {
- return mDisplaySurface->beginFrame(mustRecompose);
-}
-
-status_t DisplayDevice::prepareFrame(HWComposer& hwc,
- std::vector<CompositionInfo>& compositionData) {
- if (mId) {
- status_t error = hwc.prepare(*mId, compositionData);
- if (error != NO_ERROR) {
- return error;
- }
- }
-
- DisplaySurface::CompositionType compositionType;
- bool hasClient = hwc.hasClientComposition(mId);
- bool hasDevice = hwc.hasDeviceComposition(mId);
- if (hasClient && hasDevice) {
- compositionType = DisplaySurface::COMPOSITION_MIXED;
- } else if (hasClient) {
- compositionType = DisplaySurface::COMPOSITION_GLES;
- } else if (hasDevice) {
- compositionType = DisplaySurface::COMPOSITION_HWC;
- } else {
- // Nothing to do -- when turning the screen off we get a frame like
- // this. Call it a HWC frame since we won't be doing any GLES work but
- // will do a prepare/set cycle.
- compositionType = DisplaySurface::COMPOSITION_HWC;
- }
- return mDisplaySurface->prepareFrame(compositionType);
-}
-
-void DisplayDevice::setProtected(bool useProtected) {
- uint64_t usageFlags = GRALLOC_USAGE_HW_RENDER;
- if (useProtected) {
- usageFlags |= GRALLOC_USAGE_PROTECTED;
- }
- const int status = native_window_set_usage(mNativeWindow.get(), usageFlags);
- ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for protected content: %d", status);
-}
-
-sp<GraphicBuffer> DisplayDevice::dequeueBuffer() {
- int fd;
- ANativeWindowBuffer* buffer;
-
- status_t res = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fd);
-
- if (res != NO_ERROR) {
- ALOGE("ANativeWindow::dequeueBuffer failed for display [%s] with error: %d",
- getDisplayName().c_str(), res);
- // Return fast here as we can't do much more - any rendering we do
- // now will just be wrong.
- return mGraphicBuffer;
- }
-
- ALOGW_IF(mGraphicBuffer != nullptr, "Clobbering a non-null pointer to a buffer [%p].",
- mGraphicBuffer->getNativeBuffer()->handle);
- mGraphicBuffer = GraphicBuffer::from(buffer);
-
- // Block until the buffer is ready
- // TODO(alecmouri): it's perhaps more appropriate to block renderengine so
- // that the gl driver can block instead.
- if (fd >= 0) {
- sync_wait(fd, -1);
- close(fd);
- }
-
- return mGraphicBuffer;
-}
-
-void DisplayDevice::queueBuffer(HWComposer& hwc) {
- if (hwc.hasClientComposition(mId) || hwc.hasFlipClientTargetRequest(mId)) {
- // hasFlipClientTargetRequest could return true even if we haven't
- // dequeued a buffer before. Try dequeueing one if we don't have a
- // buffer ready.
- if (mGraphicBuffer == nullptr) {
- ALOGI("Attempting to queue a client composited buffer without one "
- "previously dequeued for display [%s]. Attempting to dequeue "
- "a scratch buffer now",
- mDisplayName.c_str());
- // We shouldn't deadlock here, since mGraphicBuffer == nullptr only
- // after a successful call to queueBuffer, or if dequeueBuffer has
- // never been called.
- dequeueBuffer();
- }
-
- if (mGraphicBuffer == nullptr) {
- ALOGE("No buffer is ready for display [%s]", mDisplayName.c_str());
- } else {
- status_t res = mNativeWindow->queueBuffer(mNativeWindow.get(),
- mGraphicBuffer->getNativeBuffer(),
- dup(mBufferReady));
- if (res != NO_ERROR) {
- ALOGE("Error when queueing buffer for display [%s]: %d", mDisplayName.c_str(), res);
- // We risk blocking on dequeueBuffer if the primary display failed
- // to queue up its buffer, so crash here.
- if (isPrimary()) {
- LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", res);
- } else {
- mNativeWindow->cancelBuffer(mNativeWindow.get(),
- mGraphicBuffer->getNativeBuffer(),
- dup(mBufferReady));
- }
- }
-
- mBufferReady.reset();
- mGraphicBuffer = nullptr;
- }
- }
-
- status_t result = mDisplaySurface->advanceFrame();
- if (result != NO_ERROR) {
- ALOGE("[%s] failed pushing new frame to HWC: %d", mDisplayName.c_str(), result);
- }
-}
-
-void DisplayDevice::onPresentDisplayCompleted() {
- mDisplaySurface->onFrameCommitted();
-}
-
-void DisplayDevice::setViewportAndProjection() const {
- size_t w = mDisplayWidth;
- size_t h = mDisplayHeight;
- Rect sourceCrop(0, 0, w, h);
- mFlinger->getRenderEngine().setViewportAndProjection(w, h, sourceCrop, ui::Transform::ROT_0);
-}
-
-void DisplayDevice::finishBuffer() {
- mBufferReady = mFlinger->getRenderEngine().flush();
- if (mBufferReady.get() < 0) {
- mFlinger->getRenderEngine().finish();
- }
-}
-
-const sp<Fence>& DisplayDevice::getClientTargetAcquireFence() const {
- return mDisplaySurface->getClientTargetAcquireFence();
+ return mCompositionDisplay->getRenderSurface()->getPageFlipCount();
}
// ----------------------------------------------------------------------------
@@ -494,21 +134,10 @@
return mLayersNeedingFences;
}
-Region DisplayDevice::getDirtyRegion(bool repaintEverything) const {
- Region dirty;
- if (repaintEverything) {
- dirty.set(getBounds());
- } else {
- const ui::Transform& planeTransform(mGlobalTransform);
- dirty = planeTransform.transform(this->dirtyRegion);
- dirty.andSelf(getBounds());
- }
- return dirty;
-}
-
// ----------------------------------------------------------------------------
void DisplayDevice::setPowerMode(int mode) {
mPowerMode = mode;
+ getCompositionDisplay()->setCompositionEnabled(mPowerMode != HWC_POWER_MODE_OFF);
}
int DisplayDevice::getPowerMode() const {
@@ -529,88 +158,37 @@
}
// ----------------------------------------------------------------------------
-void DisplayDevice::setActiveColorMode(ColorMode mode) {
- mActiveColorMode = mode;
-}
-
-ColorMode DisplayDevice::getActiveColorMode() const {
- return mActiveColorMode;
-}
-
-RenderIntent DisplayDevice::getActiveRenderIntent() const {
- return mActiveRenderIntent;
-}
-
-void DisplayDevice::setActiveRenderIntent(RenderIntent renderIntent) {
- mActiveRenderIntent = renderIntent;
-}
-
-void DisplayDevice::setColorTransform(const mat4& transform) {
- const bool isIdentity = (transform == mat4());
- mColorTransform =
- isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
-}
-
-android_color_transform_t DisplayDevice::getColorTransform() const {
- return mColorTransform;
-}
-
-void DisplayDevice::setCompositionDataSpace(ui::Dataspace dataspace) {
- mCompositionDataSpace = dataspace;
- ANativeWindow* const window = mNativeWindow.get();
- native_window_set_buffers_data_space(window, static_cast<android_dataspace>(dataspace));
-}
ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
- return mCompositionDataSpace;
+ return mCompositionDisplay->getState().dataspace;
}
// ----------------------------------------------------------------------------
void DisplayDevice::setLayerStack(uint32_t stack) {
- mLayerStack = stack;
- dirtyRegion.set(bounds());
+ mCompositionDisplay->setLayerStackFilter(!isPrimary(), stack);
}
// ----------------------------------------------------------------------------
-uint32_t DisplayDevice::getOrientationTransform() const {
- uint32_t transform = 0;
- switch (mOrientation) {
- case DisplayState::eOrientationDefault:
- transform = ui::Transform::ROT_0;
- break;
- case DisplayState::eOrientation90:
- transform = ui::Transform::ROT_90;
- break;
- case DisplayState::eOrientation180:
- transform = ui::Transform::ROT_180;
- break;
- case DisplayState::eOrientation270:
- transform = ui::Transform::ROT_270;
- break;
- }
- return transform;
-}
-
-status_t DisplayDevice::orientationToTransfrom(
- int orientation, int w, int h, ui::Transform* tr)
-{
- uint32_t flags = 0;
+uint32_t DisplayDevice::displayStateOrientationToTransformOrientation(int orientation) {
switch (orientation) {
case DisplayState::eOrientationDefault:
- flags = ui::Transform::ROT_0;
- break;
+ return ui::Transform::ROT_0;
case DisplayState::eOrientation90:
- flags = ui::Transform::ROT_90;
- break;
+ return ui::Transform::ROT_90;
case DisplayState::eOrientation180:
- flags = ui::Transform::ROT_180;
- break;
+ return ui::Transform::ROT_180;
case DisplayState::eOrientation270:
- flags = ui::Transform::ROT_270;
- break;
+ return ui::Transform::ROT_270;
default:
+ return ui::Transform::ROT_INVALID;
+ }
+}
+
+status_t DisplayDevice::orientationToTransfrom(int orientation, int w, int h, ui::Transform* tr) {
+ uint32_t flags = displayStateOrientationToTransformOrientation(orientation);
+ if (flags == ui::Transform::ROT_INVALID) {
return BAD_VALUE;
}
tr->set(flags, w, h);
@@ -618,12 +196,7 @@
}
void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) {
- dirtyRegion.set(getBounds());
-
- mDisplaySurface->resizeBuffers(newWidth, newHeight);
-
- mDisplayWidth = newWidth;
- mDisplayHeight = newHeight;
+ mCompositionDisplay->setBounds(ui::Size(newWidth, newHeight));
}
void DisplayDevice::setProjection(int orientation,
@@ -631,8 +204,11 @@
Rect viewport(newViewport);
Rect frame(newFrame);
- const int w = mDisplayWidth;
- const int h = mDisplayHeight;
+ mOrientation = orientation;
+
+ const Rect& displayBounds = getCompositionDisplay()->getState().bounds;
+ const int w = displayBounds.width();
+ const int h = displayBounds.height();
ui::Transform R;
DisplayDevice::orientationToTransfrom(orientation, w, h, &R);
@@ -656,8 +232,6 @@
}
}
- dirtyRegion.set(getBounds());
-
ui::Transform TL, TP, S;
float src_width = viewport.width();
float src_height = viewport.height();
@@ -676,7 +250,7 @@
TL.set(-src_x, -src_y);
TP.set(dst_x, dst_y);
- // need to take care of primary display rotation for mGlobalTransform
+ // need to take care of primary display rotation for globalTransform
// for case if the panel is not installed aligned with device orientation
if (isPrimary()) {
DisplayDevice::orientationToTransfrom(
@@ -687,38 +261,25 @@
// The viewport and frame are both in the logical orientation.
// Apply the logical translation, scale to physical size, apply the
// physical translation and finally rotate to the physical orientation.
- mGlobalTransform = R * TP * S * TL;
+ ui::Transform globalTransform = R * TP * S * TL;
- const uint8_t type = mGlobalTransform.getType();
- mNeedsFiltering = (!mGlobalTransform.preserveRects() ||
- (type >= ui::Transform::SCALE));
+ const uint8_t type = globalTransform.getType();
+ const bool needsFiltering =
+ (!globalTransform.preserveRects() || (type >= ui::Transform::SCALE));
- mScissor = mGlobalTransform.transform(viewport);
- if (mScissor.isEmpty()) {
- mScissor = getBounds();
+ Rect scissor = globalTransform.transform(viewport);
+ if (scissor.isEmpty()) {
+ scissor = displayBounds;
}
- mOrientation = orientation;
if (isPrimary()) {
- uint32_t transform = 0;
- switch (mOrientation) {
- case DisplayState::eOrientationDefault:
- transform = ui::Transform::ROT_0;
- break;
- case DisplayState::eOrientation90:
- transform = ui::Transform::ROT_90;
- break;
- case DisplayState::eOrientation180:
- transform = ui::Transform::ROT_180;
- break;
- case DisplayState::eOrientation270:
- transform = ui::Transform::ROT_270;
- break;
- }
- sPrimaryDisplayOrientation = transform;
+ sPrimaryDisplayOrientation = displayStateOrientationToTransformOrientation(orientation);
}
- mViewport = viewport;
- mFrame = frame;
+
+ getCompositionDisplay()->setProjection(globalTransform,
+ displayStateOrientationToTransformOrientation(
+ orientation),
+ frame, viewport, scissor, needsFiltering);
}
uint32_t DisplayDevice::getPrimaryDisplayOrientationTransform() {
@@ -726,149 +287,94 @@
}
std::string DisplayDevice::getDebugName() const {
- const auto id = mId ? to_string(*mId) + ", " : std::string();
+ const auto id = getId() ? to_string(*getId()) + ", " : std::string();
return base::StringPrintf("DisplayDevice{%s%s%s\"%s\"}", id.c_str(),
isPrimary() ? "primary, " : "", isVirtual() ? "virtual, " : "",
mDisplayName.c_str());
}
void DisplayDevice::dump(std::string& result) const {
- const ui::Transform& tr(mGlobalTransform);
- ANativeWindow* const window = mNativeWindow.get();
StringAppendF(&result, "+ %s\n", getDebugName().c_str());
- StringAppendF(&result,
- " layerStack=%u, (%4dx%4d), ANativeWindow=%p "
- "format=%d, orient=%2d (type=%08x), flips=%u, isSecure=%d, "
- "powerMode=%d, activeConfig=%d, numLayers=%zu\n",
- mLayerStack, mDisplayWidth, mDisplayHeight, window,
- ANativeWindow_getFormat(window), mOrientation, tr.getType(), getPageFlipCount(),
- mIsSecure, mPowerMode, mActiveConfig, mVisibleLayersSortedByZ.size());
- StringAppendF(&result,
- " v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
- "transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
- mViewport.left, mViewport.top, mViewport.right, mViewport.bottom, mFrame.left,
- mFrame.top, mFrame.right, mFrame.bottom, mScissor.left, mScissor.top,
- mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0], tr[0][1], tr[1][1],
- tr[2][1], tr[0][2], tr[1][2], tr[2][2]);
- auto const surface = static_cast<Surface*>(window);
- ui::Dataspace dataspace = surface->getBuffersDataSpace();
- StringAppendF(&result,
- " wideColorGamut=%d, hdr10plus =%d, hdr10=%d, colorMode=%s, dataspace: %s "
- "(%d)\n",
- mHasWideColorGamut, mHasHdr10Plus, mHasHdr10,
- decodeColorMode(mActiveColorMode).c_str(),
- dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(), dataspace);
- String8 surfaceDump;
- mDisplaySurface->dumpAsString(surfaceDump);
- result.append(surfaceDump.string(), surfaceDump.size());
+ result.append(" ");
+ StringAppendF(&result, "powerMode=%d, ", mPowerMode);
+ StringAppendF(&result, "activeConfig=%d, ", mActiveConfig);
+ StringAppendF(&result, "numLayers=%zu\n", mVisibleLayersSortedByZ.size());
+ getCompositionDisplay()->dump(result);
}
-// Map dataspace/intent to the best matched dataspace/colorMode/renderIntent
-// supported by HWC.
-void DisplayDevice::addColorMode(
- const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes,
- const ColorMode mode, const RenderIntent intent) {
- // find the best color mode
- const ColorMode hwcColorMode = getHwcColorMode(hwcColorModes, mode);
-
- // find the best render intent
- auto iter = hwcColorModes.find(hwcColorMode);
- const auto& hwcIntents =
- iter != hwcColorModes.end() ? iter->second : std::vector<RenderIntent>();
- const RenderIntent hwcIntent = getHwcRenderIntent(hwcIntents, intent);
-
- const Dataspace dataspace = colorModeToDataspace(mode);
- const Dataspace hwcDataspace = colorModeToDataspace(hwcColorMode);
-
- ALOGV("%s: map (%s, %s) to (%s, %s, %s)", getDebugName().c_str(),
- dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
- decodeRenderIntent(intent).c_str(),
- dataspaceDetails(static_cast<android_dataspace_t>(hwcDataspace)).c_str(),
- decodeColorMode(hwcColorMode).c_str(), decodeRenderIntent(hwcIntent).c_str());
-
- mColorModes[getColorModeKey(dataspace, intent)] = {hwcDataspace, hwcColorMode, hwcIntent};
+bool DisplayDevice::hasRenderIntent(ui::RenderIntent intent) const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasRenderIntent(intent);
}
-void DisplayDevice::populateColorModes(
- const std::unordered_map<ColorMode, std::vector<RenderIntent>>& hwcColorModes) {
- if (!hasWideColorGamut()) {
- return;
- }
+// ----------------------------------------------------------------------------
- // collect all known SDR render intents
- std::unordered_set<RenderIntent> sdrRenderIntents(sSdrRenderIntents.begin(),
- sSdrRenderIntents.end());
- auto iter = hwcColorModes.find(ColorMode::SRGB);
- if (iter != hwcColorModes.end()) {
- for (auto intent : iter->second) {
- sdrRenderIntents.insert(intent);
- }
- }
-
- // add all known SDR combinations
- for (auto intent : sdrRenderIntents) {
- for (auto mode : sSdrColorModes) {
- addColorMode(hwcColorModes, mode, intent);
- }
- }
-
- // collect all known HDR render intents
- std::unordered_set<RenderIntent> hdrRenderIntents(sHdrRenderIntents.begin(),
- sHdrRenderIntents.end());
- iter = hwcColorModes.find(ColorMode::BT2100_PQ);
- if (iter != hwcColorModes.end()) {
- for (auto intent : iter->second) {
- hdrRenderIntents.insert(intent);
- }
- }
-
- // add all known HDR combinations
- for (auto intent : sHdrRenderIntents) {
- for (auto mode : sHdrColorModes) {
- addColorMode(hwcColorModes, mode, intent);
- }
- }
+const std::optional<DisplayId>& DisplayDevice::getId() const {
+ return mCompositionDisplay->getId();
}
-bool DisplayDevice::hasRenderIntent(RenderIntent intent) const {
- // assume a render intent is supported when SRGB supports it; we should
- // get rid of that assumption.
- auto iter = mColorModes.find(getColorModeKey(Dataspace::V0_SRGB, intent));
- return iter != mColorModes.end() && iter->second.renderIntent == intent;
+bool DisplayDevice::isSecure() const {
+ return mCompositionDisplay->isSecure();
}
-bool DisplayDevice::hasLegacyHdrSupport(Dataspace dataspace) const {
- if ((dataspace == Dataspace::BT2020_PQ && hasHDR10Support()) ||
- (dataspace == Dataspace::BT2020_HLG && hasHLGSupport())) {
- auto iter =
- mColorModes.find(getColorModeKey(dataspace, RenderIntent::TONE_MAP_COLORIMETRIC));
- return iter == mColorModes.end() || iter->second.dataspace != dataspace;
- }
-
- return false;
+const Rect& DisplayDevice::getBounds() const {
+ return mCompositionDisplay->getState().bounds;
}
-void DisplayDevice::getBestColorMode(Dataspace dataspace, RenderIntent intent,
- Dataspace* outDataspace, ColorMode* outMode,
- RenderIntent* outIntent) const {
- auto iter = mColorModes.find(getColorModeKey(dataspace, intent));
- if (iter != mColorModes.end()) {
- *outDataspace = iter->second.dataspace;
- *outMode = iter->second.colorMode;
- *outIntent = iter->second.renderIntent;
- } else {
- // this is unexpected on a WCG display
- if (hasWideColorGamut()) {
- ALOGE("map unknown (%s)/(%s) to default color mode",
- dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
- decodeRenderIntent(intent).c_str());
- }
+const Region& DisplayDevice::getUndefinedRegion() const {
+ return mCompositionDisplay->getState().undefinedRegion;
+}
- *outDataspace = Dataspace::UNKNOWN;
- *outMode = ColorMode::NATIVE;
- *outIntent = RenderIntent::COLORIMETRIC;
- }
+bool DisplayDevice::needsFiltering() const {
+ return mCompositionDisplay->getState().needsFiltering;
+}
+
+uint32_t DisplayDevice::getLayerStack() const {
+ return mCompositionDisplay->getState().singleLayerStackId;
+}
+
+const ui::Transform& DisplayDevice::getTransform() const {
+ return mCompositionDisplay->getState().transform;
+}
+
+const Rect& DisplayDevice::getViewport() const {
+ return mCompositionDisplay->getState().viewport;
+}
+
+const Rect& DisplayDevice::getFrame() const {
+ return mCompositionDisplay->getState().frame;
+}
+
+const Rect& DisplayDevice::getScissor() const {
+ return mCompositionDisplay->getState().scissor;
+}
+
+bool DisplayDevice::hasWideColorGamut() const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasWideColorGamut();
+}
+
+bool DisplayDevice::hasHDR10PlusSupport() const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasHDR10PlusSupport();
+}
+
+bool DisplayDevice::hasHDR10Support() const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasHDR10Support();
+}
+
+bool DisplayDevice::hasHLGSupport() const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasHLGSupport();
+}
+
+bool DisplayDevice::hasDolbyVisionSupport() const {
+ return mCompositionDisplay->getDisplayColorProfile()->hasDolbyVisionSupport();
+}
+
+int DisplayDevice::getSupportedPerFrameMetadata() const {
+ return mCompositionDisplay->getDisplayColorProfile()->getSupportedPerFrameMetadata();
+}
+
+const HdrCapabilities& DisplayDevice::getHdrCapabilities() const {
+ return mCompositionDisplay->getDisplayColorProfile()->getHdrCapabilities();
}
std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 250a650..9674f0d 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -44,7 +44,6 @@
namespace android {
-class DisplaySurface;
class Fence;
class HWComposer;
class IGraphicBufferProducer;
@@ -55,35 +54,33 @@
struct DisplayDeviceCreationArgs;
struct DisplayInfo;
-class DisplayDevice : public LightRefBase<DisplayDevice>
-{
+namespace compositionengine {
+class Display;
+class DisplaySurface;
+} // namespace compositionengine
+
+class DisplayDevice : public LightRefBase<DisplayDevice> {
public:
constexpr static float sDefaultMinLumiance = 0.0;
constexpr static float sDefaultMaxLumiance = 500.0;
- // region in layer-stack space
- mutable Region dirtyRegion;
- // region in screen space
- Region undefinedRegion;
- bool lastCompositionHadVisibleLayers;
-
enum {
NO_LAYER_STACK = 0xFFFFFFFF,
};
explicit DisplayDevice(DisplayDeviceCreationArgs&& args);
- ~DisplayDevice();
+ virtual ~DisplayDevice();
+
+ std::shared_ptr<compositionengine::Display> getCompositionDisplay() const {
+ return mCompositionDisplay;
+ }
bool isVirtual() const { return mIsVirtual; }
bool isPrimary() const { return mIsPrimary; }
// isSecure indicates whether this display can be trusted to display
// secure surfaces.
- bool isSecure() const { return mIsSecure; }
-
- // Flip the front and back buffers if the back buffer is "dirty". Might
- // be instantaneous, might involve copying the frame buffer around.
- void flip() const;
+ bool isSecure() const;
int getWidth() const;
int getHeight() const;
@@ -93,44 +90,34 @@
const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const;
void setLayersNeedingFences(const Vector< sp<Layer> >& layers);
const Vector< sp<Layer> >& getLayersNeedingFences() const;
- Region getDirtyRegion(bool repaintEverything) const;
void setLayerStack(uint32_t stack);
void setDisplaySize(const int newWidth, const int newHeight);
void setProjection(int orientation, const Rect& viewport, const Rect& frame);
int getOrientation() const { return mOrientation; }
- uint32_t getOrientationTransform() const;
static uint32_t getPrimaryDisplayOrientationTransform();
- const ui::Transform& getTransform() const { return mGlobalTransform; }
- const Rect getViewport() const { return mViewport; }
- const Rect getFrame() const { return mFrame; }
- const Rect& getScissor() const { return mScissor; }
- bool needsFiltering() const { return mNeedsFiltering; }
+ const ui::Transform& getTransform() const;
+ const Rect& getViewport() const;
+ const Rect& getFrame() const;
+ const Rect& getScissor() const;
+ bool needsFiltering() const;
+ uint32_t getLayerStack() const;
- uint32_t getLayerStack() const { return mLayerStack; }
-
- const std::optional<DisplayId>& getId() const { return mId; }
+ const std::optional<DisplayId>& getId() const;
const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
int32_t getSequenceId() const { return mSequenceId; }
- int32_t getSupportedPerFrameMetadata() const { return mSupportedPerFrameMetadata; }
+ const Region& getUndefinedRegion() const;
- // We pass in mustRecompose so we can keep VirtualDisplaySurface's state
- // machine happy without actually queueing a buffer if nothing has changed
- status_t beginFrame(bool mustRecompose) const;
- status_t prepareFrame(HWComposer& hwc, std::vector<CompositionInfo>& compositionInfo);
+ int32_t getSupportedPerFrameMetadata() const;
- bool hasWideColorGamut() const { return mHasWideColorGamut; }
+ bool hasWideColorGamut() const;
// Whether h/w composer has native support for specific HDR type.
- bool hasHDR10PlusSupport() const { return mHasHdr10Plus; }
- bool hasHDR10Support() const { return mHasHdr10; }
- bool hasHLGSupport() const { return mHasHLG; }
- bool hasDolbyVisionSupport() const { return mHasDolbyVision; }
-
- // Return true if the HDR dataspace is supported but
- // there is no corresponding color mode.
- bool hasLegacyHdrSupport(ui::Dataspace dataspace) const;
+ bool hasHDR10PlusSupport() const;
+ bool hasHDR10Support() const;
+ bool hasHLGSupport() const;
+ bool hasDolbyVisionSupport() const;
// The returned HdrCapabilities is the combination of HDR capabilities from
// hardware composer and RenderEngine. When the DisplayDevice supports wide
@@ -138,41 +125,17 @@
// color space for both PQ and HLG HDR contents. The minimum and maximum
// luminance will be set to sDefaultMinLumiance and sDefaultMaxLumiance
// respectively if hardware composer doesn't return meaningful values.
- const HdrCapabilities& getHdrCapabilities() const { return mHdrCapabilities; }
+ const HdrCapabilities& getHdrCapabilities() const;
// Return true if intent is supported by the display.
bool hasRenderIntent(ui::RenderIntent intent) const;
- void getBestColorMode(ui::Dataspace dataspace, ui::RenderIntent intent,
- ui::Dataspace* outDataspace, ui::ColorMode* outMode,
- ui::RenderIntent* outIntent) const;
-
- void setProtected(bool useProtected);
- // Queues the drawn buffer for consumption by HWC.
- void queueBuffer(HWComposer& hwc);
- // Allocates a buffer as scratch space for GPU composition
- sp<GraphicBuffer> dequeueBuffer();
-
- // called after h/w composer has completed its set() call
- void onPresentDisplayCompleted();
-
- Rect getBounds() const {
- return Rect(mDisplayWidth, mDisplayHeight);
- }
- inline Rect bounds() const { return getBounds(); }
+ const Rect& getBounds() const;
+ const Rect& bounds() const { return getBounds(); }
void setDisplayName(const std::string& displayName);
const std::string& getDisplayName() const { return mDisplayName; }
- // Acquires a new buffer for GPU composition.
- void readyNewBuffer();
- // Marks the current buffer has finished, so that it can be presented and
- // swapped out.
- void finishBuffer();
- void setViewportAndProjection() const;
-
- const sp<Fence>& getClientTargetAcquireFence() const;
-
/* ------------------------------------------------------------------------
* Display power mode management.
*/
@@ -180,13 +143,6 @@
void setPowerMode(int mode);
bool isPoweredOn() const;
- ui::ColorMode getActiveColorMode() const;
- void setActiveColorMode(ui::ColorMode mode);
- ui::RenderIntent getActiveRenderIntent() const;
- void setActiveRenderIntent(ui::RenderIntent renderIntent);
- android_color_transform_t getColorTransform() const;
- void setColorTransform(const mat4& transform);
- void setCompositionDataSpace(ui::Dataspace dataspace);
ui::Dataspace getCompositionDataSpace() const;
/* ------------------------------------------------------------------------
@@ -196,7 +152,7 @@
void setActiveConfig(int mode);
// release HWC resources (if any) for removable displays
- void disconnect(HWComposer& hwc);
+ void disconnect();
/* ------------------------------------------------------------------------
* Debugging
@@ -206,29 +162,18 @@
void dump(std::string& result) const;
private:
+ /*
+ * Constants, set during initialization
+ */
const sp<SurfaceFlinger> mFlinger;
const wp<IBinder> mDisplayToken;
const int32_t mSequenceId;
- std::optional<DisplayId> mId;
+ const int mDisplayInstallOrientation;
+ const std::shared_ptr<compositionengine::Display> mCompositionDisplay;
- // ANativeWindow this display is rendering into
- sp<ANativeWindow> mNativeWindow;
- // Current buffer that this display can render to.
- sp<GraphicBuffer> mGraphicBuffer;
- sp<DisplaySurface> mDisplaySurface;
- // File descriptor indicating that mGraphicBuffer is ready for display, i.e.
- // that drawing to the buffer is now complete.
- base::unique_fd mBufferReady;
-
- int mDisplayWidth;
- int mDisplayHeight;
- const int mDisplayInstallOrientation;
- mutable uint32_t mPageFlipCount;
- std::string mDisplayName;
-
+ std::string mDisplayName;
const bool mIsVirtual;
- const bool mIsSecure;
/*
* Can only accessed from the main thread, these members
@@ -243,66 +188,17 @@
/*
* Transaction state
*/
+ static uint32_t displayStateOrientationToTransformOrientation(int orientation);
static status_t orientationToTransfrom(int orientation,
int w, int h, ui::Transform* tr);
- // The identifier of the active layer stack for this display. Several displays
- // can use the same layer stack: A z-ordered group of layers (sometimes called
- // "surfaces"). Any given layer can only be on a single layer stack.
- uint32_t mLayerStack;
-
int mOrientation;
static uint32_t sPrimaryDisplayOrientation;
- // user-provided visible area of the layer stack
- Rect mViewport;
- // user-provided rectangle where mViewport gets mapped to
- Rect mFrame;
- // pre-computed scissor to apply to the display
- Rect mScissor;
- ui::Transform mGlobalTransform;
- bool mNeedsFiltering;
+
// Current power mode
int mPowerMode;
// Current active config
int mActiveConfig;
- // current active color mode
- ui::ColorMode mActiveColorMode = ui::ColorMode::NATIVE;
- // Current active render intent.
- ui::RenderIntent mActiveRenderIntent = ui::RenderIntent::COLORIMETRIC;
- ui::Dataspace mCompositionDataSpace = ui::Dataspace::UNKNOWN;
- // Current color transform
- android_color_transform_t mColorTransform;
-
- // Need to know if display is wide-color capable or not.
- // Initialized by SurfaceFlinger when the DisplayDevice is created.
- // Fed to RenderEngine during composition.
- bool mHasWideColorGamut;
- bool mHasHdr10Plus;
- bool mHasHdr10;
- bool mHasHLG;
- bool mHasDolbyVision;
- HdrCapabilities mHdrCapabilities;
- const int32_t mSupportedPerFrameMetadata;
-
- // Mappings from desired Dataspace/RenderIntent to the supported
- // Dataspace/ColorMode/RenderIntent.
- using ColorModeKey = uint64_t;
- struct ColorModeValue {
- ui::Dataspace dataspace;
- ui::ColorMode colorMode;
- ui::RenderIntent renderIntent;
- };
-
- static ColorModeKey getColorModeKey(ui::Dataspace dataspace, ui::RenderIntent intent) {
- return (static_cast<uint64_t>(dataspace) << 32) | static_cast<uint32_t>(intent);
- }
- void populateColorModes(
- const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hwcColorModes);
- void addColorMode(
- const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>& hwcColorModes,
- const ui::ColorMode mode, const ui::RenderIntent intent);
-
- std::unordered_map<ColorModeKey, ColorModeValue> mColorModes;
// TODO(b/74619554): Remove special cases for primary display.
const bool mIsPrimary;
@@ -341,7 +237,7 @@
bool isVirtual{false};
bool isSecure{false};
sp<ANativeWindow> nativeWindow;
- sp<DisplaySurface> displaySurface;
+ sp<compositionengine::DisplaySurface> displaySurface;
int displayInstallOrientation{DisplayState::eOrientationDefault};
bool hasWideColorGamut{false};
HdrCapabilities hdrCapabilities;
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 2431dfd..18c524f 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -17,15 +17,15 @@
#ifndef ANDROID_SF_FRAMEBUFFER_SURFACE_H
#define ANDROID_SF_FRAMEBUFFER_SURFACE_H
-#include "DisplayIdentification.h"
-#include "DisplaySurface.h"
-#include "HWComposerBufferCache.h"
-
#include <stdint.h>
#include <sys/types.h>
+#include <compositionengine/DisplaySurface.h>
#include <gui/ConsumerBase.h>
+#include "DisplayIdentification.h"
+#include "HWComposerBufferCache.h"
+
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
@@ -36,8 +36,7 @@
// ---------------------------------------------------------------------------
-class FramebufferSurface : public ConsumerBase,
- public DisplaySurface {
+class FramebufferSurface : public ConsumerBase, public compositionengine::DisplaySurface {
public:
FramebufferSurface(HWComposer& hwc, DisplayId displayId,
const sp<IGraphicBufferConsumer>& consumer);
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 27d3dc5..1c2853a 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -38,12 +38,16 @@
#define VDS_LOGV(msg, ...) ALOGV("[%s] " msg, \
mDisplayName.c_str(), ##__VA_ARGS__)
-static const char* dbgCompositionTypeStr(DisplaySurface::CompositionType type) {
+static const char* dbgCompositionTypeStr(compositionengine::DisplaySurface::CompositionType type) {
switch (type) {
- case DisplaySurface::COMPOSITION_UNKNOWN: return "UNKNOWN";
- case DisplaySurface::COMPOSITION_GLES: return "GLES";
- case DisplaySurface::COMPOSITION_HWC: return "HWC";
- case DisplaySurface::COMPOSITION_MIXED: return "MIXED";
+ case compositionengine::DisplaySurface::COMPOSITION_UNKNOWN:
+ return "UNKNOWN";
+ case compositionengine::DisplaySurface::COMPOSITION_GLES:
+ return "GLES";
+ case compositionengine::DisplaySurface::COMPOSITION_HWC:
+ return "HWC";
+ case compositionengine::DisplaySurface::COMPOSITION_MIXED:
+ return "MIXED";
default: return "<INVALID>";
}
}
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 33678df..87ae7dd 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -20,13 +20,13 @@
#include <optional>
#include <string>
-#include "DisplayIdentification.h"
-#include "DisplaySurface.h"
-#include "HWComposerBufferCache.h"
-
+#include <compositionengine/DisplaySurface.h>
#include <gui/ConsumerBase.h>
#include <gui/IGraphicBufferProducer.h>
+#include "DisplayIdentification.h"
+#include "HWComposerBufferCache.h"
+
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
@@ -73,7 +73,7 @@
* the HWC output buffer. When HWC composition is complete, the scratch buffer
* is released and the output buffer is queued to the sink.
*/
-class VirtualDisplaySurface : public DisplaySurface,
+class VirtualDisplaySurface : public compositionengine::DisplaySurface,
public BnGraphicBufferProducer,
private ConsumerBase {
public:
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index ee49610..aa9bc15 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2135,7 +2135,7 @@
return mRemovedFromCurrentState;
}
-InputWindowInfo Layer::fillInputInfo(const Rect& screenBounds) {
+InputWindowInfo Layer::fillInputInfo() {
InputWindowInfo info = mDrawingState.inputInfo;
ui::Transform t = getTransform();
@@ -2148,20 +2148,18 @@
}
// Transform layer size to screen space and inset it by surface insets.
- Rect layerBounds = getCroppedBufferSize(getDrawingState());
+ Rect layerBounds = getBufferSize(getDrawingState());
+ if (!layerBounds.isValid()) {
+ layerBounds = getCroppedBufferSize(getDrawingState());
+ }
layerBounds = t.transform(layerBounds);
layerBounds.inset(info.surfaceInset, info.surfaceInset, info.surfaceInset, info.surfaceInset);
- // Intersect with screen bounds to shrink the frame by the surface insets. The surface insets
- // are not set on the screen bounds directly since the surface inset region may already be
- // cropped by a parent layer.
- Rect frame;
- screenBounds.intersect(layerBounds, &frame);
-
- info.frameLeft = frame.left;
- info.frameTop = frame.top;
- info.frameRight = frame.right;
- info.frameBottom = frame.bottom;
+ // Input coordinate should match the layer bounds.
+ info.frameLeft = layerBounds.left;
+ info.frameTop = layerBounds.top;
+ info.frameRight = layerBounds.right;
+ info.frameBottom = layerBounds.bottom;
// Position the touchable region relative to frame screen location and restrict it to frame
// bounds.
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 7bc7a82..95a8630 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -773,7 +773,7 @@
bool mPendingHWCDestroy{false};
void setInputInfo(const InputWindowInfo& info);
- InputWindowInfo fillInputInfo(const Rect& screenBounds);
+ InputWindowInfo fillInputInfo();
bool hasInput() const;
protected:
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index b74b901..9b2a6fc 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -657,6 +657,9 @@
Mutex::Autolock lock(mMutex);
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
nsecs_t phase = mReferenceTime + mPhase;
+ if (mPeriod == 0) {
+ return 0;
+ }
return (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1af1112..5df2876 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -37,6 +37,10 @@
#include <binder/PermissionCache.h>
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/OutputCompositionState.h>
#include <dvr/vr_flinger.h>
#include <gui/BufferQueue.h>
#include <gui/GuiConfig.h>
@@ -1019,40 +1023,11 @@
ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& displayToken) {
if (const auto display = getDisplayDevice(displayToken)) {
- return display->getActiveColorMode();
+ return display->getCompositionDisplay()->getState().colorMode;
}
return static_cast<ColorMode>(BAD_VALUE);
}
-void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& display, ColorMode mode,
- Dataspace dataSpace, RenderIntent renderIntent) {
- if (display->isVirtual()) {
- ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
- return;
- }
-
- ColorMode currentMode = display->getActiveColorMode();
- Dataspace currentDataSpace = display->getCompositionDataSpace();
- RenderIntent currentRenderIntent = display->getActiveRenderIntent();
-
- if (mode == currentMode && dataSpace == currentDataSpace &&
- renderIntent == currentRenderIntent) {
- return;
- }
-
- display->setActiveColorMode(mode);
- display->setCompositionDataSpace(dataSpace);
- display->setActiveRenderIntent(renderIntent);
-
- const auto displayId = display->getId();
- LOG_ALWAYS_FATAL_IF(!displayId);
- getHwComposer().setActiveColorMode(*displayId, mode, renderIntent);
-
- ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), display=%s",
- decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
- renderIntent, to_string(*displayId).c_str());
-}
-
status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
postMessageSync(new LambdaMessage([&] {
Vector<ColorMode> modes;
@@ -1071,8 +1046,8 @@
ALOGW("Attempt to set active color mode %s (%d) for virtual display",
decodeColorMode(mode).c_str(), mode);
} else {
- setActiveColorModeInternal(display, mode, Dataspace::UNKNOWN,
- RenderIntent::COLORIMETRIC);
+ display->getCompositionDisplay()->setColorMode(mode, Dataspace::UNKNOWN,
+ RenderIntent::COLORIMETRIC);
}
}));
@@ -1163,6 +1138,20 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
+ int32_t* outBufferId) {
+ if (!outBufferId) {
+ return BAD_VALUE;
+ }
+ *outBufferId = mBufferStateLayerCache.add(token, buffer);
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) {
+ mBufferStateLayerCache.release(token, bufferId);
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
postMessageSync(new LambdaMessage([&] {
Mutex::Autolock _l(mStateLock);
@@ -1688,9 +1677,11 @@
postComposition();
mHadClientComposition = false;
- for (const auto& [token, display] : mDisplays) {
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto displayId = display->getId();
mHadClientComposition =
- mHadClientComposition || getHwComposer().hasClientComposition(display->getId());
+ mHadClientComposition || getHwComposer().hasClientComposition(displayId);
}
// Setup RenderEngine sync fences if native sync is supported.
@@ -1730,13 +1721,14 @@
// build the h/w work list
if (CC_UNLIKELY(mGeometryInvalid)) {
mGeometryInvalid = false;
- for (const auto& [token, display] : mDisplays) {
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
const auto displayId = display->getId();
if (!displayId) {
continue;
}
- const Vector<sp<Layer>>& currentLayers = display->getVisibleLayersSortedByZ();
+ const Vector<sp<Layer>>& currentLayers = displayDevice->getVisibleLayersSortedByZ();
for (size_t i = 0; i < currentLayers.size(); i++) {
const auto& layer = currentLayers[i];
@@ -1747,7 +1739,7 @@
}
}
- layer->setGeometry(display, i);
+ layer->setGeometry(displayDevice, i);
if (mDebugDisableHWC || mDebugRegion) {
layer->forceClientComposition(*displayId);
}
@@ -1756,29 +1748,27 @@
}
// Set the per-frame data
- for (const auto& [token, display] : mDisplays) {
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
const auto displayId = display->getId();
if (!displayId) {
continue;
}
+ auto* profile = display->getDisplayColorProfile();
if (mDrawingState.colorMatrixChanged) {
display->setColorTransform(mDrawingState.colorMatrix);
- status_t result =
- getHwComposer().setColorTransform(*displayId, mDrawingState.colorMatrix);
- ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display %s: %d",
- to_string(*displayId).c_str(), result);
}
- for (auto& layer : display->getVisibleLayersSortedByZ()) {
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
if (layer->isHdrY410()) {
layer->forceClientComposition(*displayId);
} else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
- !display->hasHDR10Support()) {
+ !profile->hasHDR10Support()) {
layer->forceClientComposition(*displayId);
} else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
- !display->hasHLGSupport()) {
+ !profile->hasHLGSupport()) {
layer->forceClientComposition(*displayId);
}
@@ -1797,16 +1787,17 @@
continue;
}
- layer->setPerFrameData(*displayId, display->getTransform(), display->getViewport(),
- display->getSupportedPerFrameMetadata());
+ const auto& displayState = display->getState();
+ layer->setPerFrameData(*displayId, displayState.transform, displayState.viewport,
+ displayDevice->getSupportedPerFrameMetadata());
}
if (useColorManagement) {
ColorMode colorMode;
Dataspace dataSpace;
RenderIntent renderIntent;
- pickColorMode(display, &colorMode, &dataSpace, &renderIntent);
- setActiveColorModeInternal(display, colorMode, dataSpace, renderIntent);
+ pickColorMode(displayDevice, &colorMode, &dataSpace, &renderIntent);
+ display->setColorMode(colorMode, dataSpace, renderIntent);
}
}
@@ -1830,34 +1821,37 @@
}
}
-void SurfaceFlinger::doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything)
-{
+void SurfaceFlinger::doDebugFlashRegions(const sp<DisplayDevice>& displayDevice,
+ bool repaintEverything) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+
// is debugging enabled
if (CC_LIKELY(!mDebugRegion))
return;
- if (display->isPoweredOn()) {
+ if (displayState.isEnabled) {
// transform the dirty region into this screen's coordinate space
- const Region dirtyRegion(display->getDirtyRegion(repaintEverything));
+ const Region dirtyRegion = display->getPhysicalSpaceDirtyRegion(repaintEverything);
if (!dirtyRegion.isEmpty()) {
// redraw the whole screen
- doComposeSurfaces(display);
+ doComposeSurfaces(displayDevice);
// and draw the dirty region
auto& engine(getRenderEngine());
engine.fillRegionWithColor(dirtyRegion, 1, 0, 1, 1);
- display->queueBuffer(getHwComposer());
+ display->getRenderSurface()->queueBuffer();
}
}
- postFramebuffer(display);
+ postFramebuffer(displayDevice);
if (mDebugRegion > 1) {
usleep(mDebugRegion * 1000);
}
- prepareFrame(display);
+ prepareFrame(displayDevice);
}
void SurfaceFlinger::doTracing(const char* where) {
@@ -2022,16 +2016,18 @@
ASSERT_ON_STACK_GUARD();
// |mStateLock| not needed as we are on the main thread
- const auto display = getDefaultDisplayDeviceLocked();
- DEFINE_STACK_GUARD(display);
+ const auto displayDevice = getDefaultDisplayDeviceLocked();
+ DEFINE_STACK_GUARD(displayDevice);
getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
DEFINE_STACK_GUARD(glCompositionDoneFenceTime);
- if (display && getHwComposer().hasClientComposition(display->getId())) {
+ if (displayDevice && getHwComposer().hasClientComposition(displayDevice->getId())) {
glCompositionDoneFenceTime =
- std::make_shared<FenceTime>(display->getClientTargetAcquireFence());
+ std::make_shared<FenceTime>(displayDevice->getCompositionDisplay()
+ ->getRenderSurface()
+ ->getClientTargetAcquireFence());
getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
} else {
glCompositionDoneFenceTime = FenceTime::NO_FENCE;
@@ -2040,8 +2036,8 @@
ASSERT_ON_STACK_GUARD();
getBE().mDisplayTimeline.updateSignalTimes();
- mPreviousPresentFence =
- display ? getHwComposer().getPresentFence(*display->getId()) : Fence::NO_FENCE;
+ mPreviousPresentFence = displayDevice ? getHwComposer().getPresentFence(*displayDevice->getId())
+ : Fence::NO_FENCE;
auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
DEFINE_STACK_GUARD(presentFenceTime);
getBE().mDisplayTimeline.push(presentFenceTime);
@@ -2073,8 +2069,9 @@
}
mDrawingState.traverseInZOrder([&](Layer* layer) {
- bool frameLatched = layer->onPostComposition(display->getId(), glCompositionDoneFenceTime,
- presentFenceTime, compositorTiming);
+ bool frameLatched =
+ layer->onPostComposition(displayDevice->getId(), glCompositionDoneFenceTime,
+ presentFenceTime, compositorTiming);
DEFINE_STACK_GUARD(frameLatched);
if (frameLatched) {
recordBufferingStats(layer->getName().string(),
@@ -2099,7 +2096,8 @@
}
if (!hasSyncFramework) {
- if (display && getHwComposer().isConnected(*display->getId()) && display->isPoweredOn()) {
+ if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
+ displayDevice->isPoweredOn()) {
if (mUseScheduler) {
mScheduler->enableHardwareVsync();
} else {
@@ -2118,10 +2116,11 @@
std::move(presentFenceTime));
ASSERT_ON_STACK_GUARD();
- } else if (display && getHwComposer().isConnected(*display->getId())) {
+ } else if (displayDevice && getHwComposer().isConnected(*displayDevice->getId())) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
- const nsecs_t presentTime = getHwComposer().getRefreshTimestamp(*display->getId());
+ const nsecs_t presentTime =
+ getHwComposer().getRefreshTimestamp(*displayDevice->getId());
DEFINE_STACK_GUARD(presentTime);
mAnimFrameTracker.setActualPresentTime(presentTime);
@@ -2143,7 +2142,8 @@
ASSERT_ON_STACK_GUARD();
- if (display && getHwComposer().isConnected(*display->getId()) && !display->isPoweredOn()) {
+ if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
+ !displayDevice->isPoweredOn()) {
return;
}
@@ -2211,20 +2211,22 @@
invalidateHwcGeometry();
for (const auto& pair : mDisplays) {
- const auto& display = pair.second;
+ const auto& displayDevice = pair.second;
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
Region opaqueRegion;
Region dirtyRegion;
Vector<sp<Layer>> layersSortedByZ;
Vector<sp<Layer>> layersNeedingFences;
- const ui::Transform& tr = display->getTransform();
- const Rect bounds = display->getBounds();
- if (display->isPoweredOn()) {
- computeVisibleRegions(display, dirtyRegion, opaqueRegion);
+ const ui::Transform& tr = displayState.transform;
+ const Rect bounds = displayState.bounds;
+ if (displayState.isEnabled) {
+ computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);
mDrawingState.traverseInZOrder([&](Layer* layer) {
bool hwcLayerDestroyed = false;
- const auto displayId = display->getId();
- if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
+ const auto displayId = displayDevice->getId();
+ if (display->belongsInOutput(layer->getLayerStack())) {
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
drawRegion.andSelf(bounds);
@@ -2255,11 +2257,14 @@
}
});
}
- display->setVisibleLayersSortedByZ(layersSortedByZ);
- display->setLayersNeedingFences(layersNeedingFences);
- display->undefinedRegion.set(bounds);
- display->undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
- display->dirtyRegion.orSelf(dirtyRegion);
+ displayDevice->setVisibleLayersSortedByZ(layersSortedByZ);
+ displayDevice->setLayersNeedingFences(layersNeedingFences);
+
+ Region undefinedRegion{bounds};
+ undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
+
+ display->editState().undefinedRegion = undefinedRegion;
+ display->editState().dirtyRegion.orSelf(dirtyRegion);
}
}
}
@@ -2324,9 +2329,11 @@
Dataspace hdrDataSpace;
Dataspace bestDataSpace = getBestDataspace(display, &hdrDataSpace);
+ auto* profile = display->getCompositionDisplay()->getDisplayColorProfile();
+
// respect hdrDataSpace only when there is no legacy HDR support
- const bool isHdr = hdrDataSpace != Dataspace::UNKNOWN &&
- !display->hasLegacyHdrSupport(hdrDataSpace);
+ const bool isHdr =
+ hdrDataSpace != Dataspace::UNKNOWN && !profile->hasLegacyHdrSupport(hdrDataSpace);
if (isHdr) {
bestDataSpace = hdrDataSpace;
}
@@ -2345,14 +2352,16 @@
break;
}
- display->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
+ profile->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
}
-void SurfaceFlinger::beginFrame(const sp<DisplayDevice>& display)
-{
- bool dirty = !display->getDirtyRegion(false).isEmpty();
- bool empty = display->getVisibleLayersSortedByZ().size() == 0;
- bool wasEmpty = !display->lastCompositionHadVisibleLayers;
+void SurfaceFlinger::beginFrame(const sp<DisplayDevice>& displayDevice) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+
+ bool dirty = !display->getPhysicalSpaceDirtyRegion(false).isEmpty();
+ bool empty = displayDevice->getVisibleLayersSortedByZ().size() == 0;
+ bool wasEmpty = !displayState.lastCompositionHadVisibleLayers;
// If nothing has changed (!dirty), don't recompose.
// If something changed, but we don't currently have any visible layers,
@@ -2366,44 +2375,50 @@
const char flagPrefix[] = {'-', '+'};
static_cast<void>(flagPrefix);
- ALOGV_IF(display->isVirtual(), "%s: %s composition for %s (%cdirty %cempty %cwasEmpty)",
- __FUNCTION__, mustRecompose ? "doing" : "skipping", display->getDebugName().c_str(),
- flagPrefix[dirty], flagPrefix[empty], flagPrefix[wasEmpty]);
+ ALOGV_IF(displayDevice->isVirtual(), "%s: %s composition for %s (%cdirty %cempty %cwasEmpty)",
+ __FUNCTION__, mustRecompose ? "doing" : "skipping",
+ displayDevice->getDebugName().c_str(), flagPrefix[dirty], flagPrefix[empty],
+ flagPrefix[wasEmpty]);
- display->beginFrame(mustRecompose);
+ display->getRenderSurface()->beginFrame(mustRecompose);
if (mustRecompose) {
- display->lastCompositionHadVisibleLayers = !empty;
+ display->editState().lastCompositionHadVisibleLayers = !empty;
}
}
-void SurfaceFlinger::prepareFrame(const sp<DisplayDevice>& display)
-{
- if (!display->isPoweredOn()) {
+void SurfaceFlinger::prepareFrame(const sp<DisplayDevice>& displayDevice) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+
+ if (!displayState.isEnabled) {
return;
}
- status_t result = display->prepareFrame(getHwComposer(),
- getBE().mCompositionInfo[display->getDisplayToken()]);
+ status_t result = display->getRenderSurface()->prepareFrame(
+ getBE().mCompositionInfo[displayDevice->getDisplayToken()]);
ALOGE_IF(result != NO_ERROR, "prepareFrame failed for %s: %d (%s)",
- display->getDebugName().c_str(), result, strerror(-result));
+ displayDevice->getDebugName().c_str(), result, strerror(-result));
}
-void SurfaceFlinger::doComposition(const sp<DisplayDevice>& display, bool repaintEverything) {
+void SurfaceFlinger::doComposition(const sp<DisplayDevice>& displayDevice, bool repaintEverything) {
ATRACE_CALL();
ALOGV("doComposition");
- if (display->isPoweredOn()) {
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+
+ if (displayState.isEnabled) {
// transform the dirty region into this screen's coordinate space
- const Region dirtyRegion(display->getDirtyRegion(repaintEverything));
+ const Region dirtyRegion = display->getPhysicalSpaceDirtyRegion(repaintEverything);
// repaint the framebuffer (if needed)
- doDisplayComposition(display, dirtyRegion);
+ doDisplayComposition(displayDevice, dirtyRegion);
- display->dirtyRegion.clear();
- display->flip();
+ display->editState().dirtyRegion.clear();
+ display->getRenderSurface()->flip();
}
- postFramebuffer(display);
+ postFramebuffer(displayDevice);
}
void SurfaceFlinger::postFrame()
@@ -2418,20 +2433,22 @@
}
}
-void SurfaceFlinger::postFramebuffer(const sp<DisplayDevice>& display)
-{
+void SurfaceFlinger::postFramebuffer(const sp<DisplayDevice>& displayDevice) {
ATRACE_CALL();
ALOGV("postFramebuffer");
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
+ const auto displayId = display->getId();
+
mPostFramebufferTime = systemTime();
- if (display->isPoweredOn()) {
- const auto displayId = display->getId();
+ if (displayState.isEnabled) {
if (displayId) {
getHwComposer().presentAndGetReleaseFences(*displayId);
}
- display->onPresentDisplayCompleted();
- for (auto& layer : display->getVisibleLayersSortedByZ()) {
+ display->getRenderSurface()->onPresentDisplayCompleted();
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
sp<Fence> releaseFence = Fence::NO_FENCE;
// The layer buffer from the previous frame (if any) is released
@@ -2448,8 +2465,9 @@
// client target acquire fence when it is available, even though
// this is suboptimal.
if (layer->getCompositionType(displayId) == HWC2::Composition::Client) {
- releaseFence = Fence::merge("LayerRelease", releaseFence,
- display->getClientTargetAcquireFence());
+ releaseFence =
+ Fence::merge("LayerRelease", releaseFence,
+ display->getRenderSurface()->getClientTargetAcquireFence());
}
layer->getBE().onLayerDisplayed(releaseFence);
@@ -2458,10 +2476,10 @@
// We've got a list of layers needing fences, that are disjoint with
// display->getVisibleLayersSortedByZ. The best we can do is to
// supply them with the present fence.
- if (!display->getLayersNeedingFences().isEmpty()) {
+ if (!displayDevice->getLayersNeedingFences().isEmpty()) {
sp<Fence> presentFence =
displayId ? getHwComposer().getPresentFence(*displayId) : Fence::NO_FENCE;
- for (auto& layer : display->getLayersNeedingFences()) {
+ for (auto& layer : displayDevice->getLayersNeedingFences()) {
layer->getBE().onLayerDisplayed(presentFence);
}
}
@@ -2542,7 +2560,7 @@
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
const wp<IBinder>& displayToken, const std::optional<DisplayId>& displayId,
- const DisplayDeviceState& state, const sp<DisplaySurface>& dispSurface,
+ const DisplayDeviceState& state, const sp<compositionengine::DisplaySurface>& dispSurface,
const sp<IGraphicBufferProducer>& producer) {
DisplayDeviceCreationArgs creationArgs(this, displayToken, displayId);
creationArgs.sequenceId = state.sequenceId;
@@ -2603,8 +2621,8 @@
defaultColorMode = ColorMode::SRGB;
defaultDataSpace = Dataspace::V0_SRGB;
}
- setActiveColorModeInternal(display, defaultColorMode, defaultDataSpace,
- RenderIntent::COLORIMETRIC);
+ display->getCompositionDisplay()->setColorMode(defaultColorMode, defaultDataSpace,
+ RenderIntent::COLORIMETRIC);
if (!state.isVirtual()) {
LOG_ALWAYS_FATAL_IF(!displayId);
display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId));
@@ -2641,7 +2659,7 @@
// in drawing state but not in current state
if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) {
- display->disconnect(getHwComposer());
+ display->disconnect();
}
if (internalDisplayId && internalDisplayId == draw[i].displayId) {
if (mUseScheduler) {
@@ -2671,7 +2689,7 @@
// from the drawing state, so that it get re-added
// below.
if (const auto display = getDisplayDeviceLocked(displayToken)) {
- display->disconnect(getHwComposer());
+ display->disconnect();
}
mDisplays.erase(displayToken);
mDrawingState.displays.removeItemsAt(i);
@@ -2702,7 +2720,7 @@
if (draw.indexOfKey(curr.keyAt(i)) < 0) {
const DisplayDeviceState& state(curr[i]);
- sp<DisplaySurface> dispSurface;
+ sp<compositionengine::DisplaySurface> dispSurface;
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferProducer> bqProducer;
sp<IGraphicBufferConsumer> bqConsumer;
@@ -2861,7 +2879,7 @@
// if not, pick the only display it's on.
hintDisplay = nullptr;
for (const auto& [token, display] : mDisplays) {
- if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
+ if (display->getCompositionDisplay()->belongsInOutput(layer->getLayerStack())) {
if (hintDisplay) {
hintDisplay = nullptr;
break;
@@ -2944,8 +2962,7 @@
if (layer->hasInput()) {
// When calculating the screen bounds we ignore the transparent region since it may
// result in an unwanted offset.
- inputHandles.add(layer->fillInputInfo(
- layer->computeScreenBounds(false /* reduceTransparentRegion */)));
+ inputHandles.add(layer->fillInputInfo());
}
});
mInputFlinger->setInputWindows(inputHandles);
@@ -3028,11 +3045,13 @@
mTransactionCV.broadcast();
}
-void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& display,
+void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
Region& outDirtyRegion, Region& outOpaqueRegion) {
ATRACE_CALL();
ALOGV("computeVisibleRegions");
+ auto display = displayDevice->getCompositionDisplay();
+
Region aboveOpaqueLayers;
Region aboveCoveredLayers;
Region dirty;
@@ -3044,7 +3063,7 @@
const Layer::State& s(layer->getDrawingState());
// only consider the layers on the given layer stack
- if (!layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
+ if (!display->belongsInOutput(layer->getLayerStack())) {
return;
}
@@ -3168,9 +3187,10 @@
}
void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
- for (const auto& [token, display] : mDisplays) {
- if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
- display->dirtyRegion.orSelf(dirty);
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+ if (display->belongsInOutput(layer->getLayerStack())) {
+ display->editState().dirtyRegion.orSelf(dirty);
}
}
}
@@ -3257,30 +3277,35 @@
mGeometryInvalid = true;
}
-void SurfaceFlinger::doDisplayComposition(const sp<DisplayDevice>& display,
+void SurfaceFlinger::doDisplayComposition(const sp<DisplayDevice>& displayDevice,
const Region& inDirtyRegion) {
+ auto display = displayDevice->getCompositionDisplay();
+
// We only need to actually compose the display if:
// 1) It is being handled by hardware composer, which may need this to
// keep its virtual display state machine in sync, or
// 2) There is work to be done (the dirty region isn't empty)
- if (!display->getId() && inDirtyRegion.isEmpty()) {
+ if (!displayDevice->getId() && inDirtyRegion.isEmpty()) {
ALOGV("Skipping display composition");
return;
}
ALOGV("doDisplayComposition");
- if (!doComposeSurfaces(display)) return;
+ if (!doComposeSurfaces(displayDevice)) return;
// swap buffers (presentation)
- display->queueBuffer(getHwComposer());
+ display->getRenderSurface()->queueBuffer();
}
-bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& display) {
+bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice) {
ALOGV("doComposeSurfaces");
- const Region bounds(display->bounds());
- const DisplayRenderArea renderArea(display);
+ auto display = displayDevice->getCompositionDisplay();
+ const auto& displayState = display->getState();
const auto displayId = display->getId();
+
+ const Region bounds(displayState.bounds);
+ const DisplayRenderArea renderArea(displayDevice);
const bool hasClientComposition = getHwComposer().hasClientComposition(displayId);
ATRACE_INT("hasClientComposition", hasClientComposition);
@@ -3293,12 +3318,12 @@
if (hasClientComposition) {
ALOGV("hasClientComposition");
- sp<GraphicBuffer> buf = display->dequeueBuffer();
+ sp<GraphicBuffer> buf = display->getRenderSurface()->dequeueBuffer();
if (buf == nullptr) {
ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
"client composition for this frame",
- display->getDisplayName().c_str());
+ displayDevice->getDisplayName().c_str());
return false;
}
@@ -3308,17 +3333,18 @@
if (fbo->getStatus() != NO_ERROR) {
ALOGW("Binding buffer for display [%s] failed with status: %d",
- display->getDisplayName().c_str(), fbo->getStatus());
+ displayDevice->getDisplayName().c_str(), fbo->getStatus());
return false;
}
+ const auto* profile = display->getDisplayColorProfile();
Dataspace outputDataspace = Dataspace::UNKNOWN;
- if (display->hasWideColorGamut()) {
- outputDataspace = display->getCompositionDataSpace();
+ if (profile->hasWideColorGamut()) {
+ outputDataspace = displayState.dataspace;
}
getRenderEngine().setOutputDataSpace(outputDataspace);
getRenderEngine().setDisplayMaxLuminance(
- display->getHdrCapabilities().getDesiredMaxLuminance());
+ profile->getHdrCapabilities().getDesiredMaxLuminance());
const bool hasDeviceComposition = getHwComposer().hasDeviceComposition(displayId);
const bool skipClientColorTransform =
@@ -3332,7 +3358,7 @@
colorMatrix = mDrawingState.colorMatrix;
}
- display->setViewportAndProjection();
+ display->getRenderSurface()->setViewportAndProjection();
// Never touch the framebuffer if we don't have any framebuffer layers
if (hasDeviceComposition) {
@@ -3346,10 +3372,10 @@
// we start with the whole screen area and remove the scissor part
// we're left with the letterbox region
// (common case is that letterbox ends-up being empty)
- const Region letterbox = bounds.subtract(display->getScissor());
+ const Region letterbox = bounds.subtract(displayState.scissor);
// compute the area to clear
- const Region region = display->undefinedRegion.merge(letterbox);
+ const Region region = displayState.undefinedRegion.merge(letterbox);
// screen is already cleared here
if (!region.isEmpty()) {
@@ -3358,8 +3384,8 @@
}
}
- const Rect& bounds = display->getBounds();
- const Rect& scissor = display->getScissor();
+ const Rect& bounds = displayState.bounds;
+ const Rect& scissor = displayState.scissor;
if (scissor != bounds) {
// scissor doesn't match the screen's dimensions, so we
// need to clear everything outside of it and enable
@@ -3375,9 +3401,9 @@
*/
ALOGV("Rendering client layers");
- const ui::Transform& displayTransform = display->getTransform();
+ const ui::Transform& displayTransform = displayState.transform;
bool firstLayer = true;
- for (auto& layer : display->getVisibleLayersSortedByZ()) {
+ for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
const Region clip(bounds.intersect(
displayTransform.transform(layer->visibleRegion)));
ALOGV("Layer: %s", layer->getName().string());
@@ -3426,7 +3452,7 @@
if (hasClientComposition) {
getRenderEngine().setColorTransform(mat4());
getRenderEngine().disableScissor();
- display->finishBuffer();
+ display->getRenderSurface()->finishBuffer();
// Clear out error flags here so that we don't wait until next
// composition to log.
getRenderEngine().checkErrors();
@@ -3456,9 +3482,11 @@
}
if (parent == nullptr && addToCurrentState) {
mCurrentState.layersSortedByZ.add(lbc);
- } else if (parent == nullptr || parent->isRemovedFromCurrentState()) {
- ALOGE("addClientLayer called with a removed parent");
- lbc->onRemovedFromCurrentState();
+ } else if (parent == nullptr) {
+ lbc->onRemovedFromCurrentState();
+ } else if (parent->isRemovedFromCurrentState()) {
+ parent->addChild(lbc);
+ lbc->onRemovedFromCurrentState();
} else {
parent->addChild(lbc);
}
@@ -3509,8 +3537,8 @@
auto& [applyToken, transactionQueue] = *it;
while (!transactionQueue.empty()) {
- const auto& [states, displays, flags] = transactionQueue.front();
- if (composerStateContainsUnsignaledFences(states)) {
+ const auto& [states, displays, flags, desiredPresentTime] = transactionQueue.front();
+ if (!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
break;
}
applyTransactionState(states, displays, flags, mInputWindowCommands);
@@ -3544,23 +3572,33 @@
return false;
}
-bool SurfaceFlinger::composerStateContainsUnsignaledFences(const Vector<ComposerState>& states) {
+bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
+ const Vector<ComposerState>& states) {
+ const nsecs_t expectedPresentTime = mPrimaryDispSync->expectedPresentTime();
+ // Do not present if the desiredPresentTime has not passed unless it is more than one second
+ // in the future. We ignore timestamps more than 1 second in the future for stability reasons.
+ if (desiredPresentTime >= 0 && desiredPresentTime >= expectedPresentTime &&
+ desiredPresentTime < expectedPresentTime + s2ns(1)) {
+ return false;
+ }
+
for (const ComposerState& state : states) {
const layer_state_t& s = state.state;
if (!(s.what & layer_state_t::eAcquireFenceChanged)) {
continue;
}
if (s.acquireFence && s.acquireFence->getStatus() == Fence::Status::Unsignaled) {
- return true;
+ return false;
}
}
- return false;
+ return true;
}
void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& states,
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
- const InputWindowCommands& inputWindowCommands) {
+ const InputWindowCommands& inputWindowCommands,
+ int64_t desiredPresentTime) {
ATRACE_CALL();
Mutex::Autolock _l(mStateLock);
@@ -3570,8 +3608,8 @@
// If its TransactionQueue already has a pending TransactionState or if it is pending
if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() ||
- composerStateContainsUnsignaledFences(states)) {
- mTransactionQueues[applyToken].emplace(states, displays, flags);
+ !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
+ mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime);
setTransactionFlags(eTransactionNeeded);
return;
}
@@ -3933,6 +3971,11 @@
callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
}
}
+ if (what & layer_state_t::eCachedBufferChanged) {
+ sp<GraphicBuffer> buffer =
+ mBufferStateLayerCache.get(s.cachedBuffer.token, s.cachedBuffer.bufferId);
+ if (layer->setBuffer(buffer)) flags |= eTraversalNeeded;
+ }
if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
// Do not put anything that updates layer state or modifies flags after
// setTransactionCompletedListener
@@ -4161,7 +4204,7 @@
d.width = 0;
d.height = 0;
displays.add(d);
- setTransactionState(state, displays, 0, nullptr, mInputWindowCommands);
+ setTransactionState(state, displays, 0, nullptr, mInputWindowCommands, -1);
setPowerModeInternal(display, HWC_POWER_MODE_NORMAL);
@@ -4655,7 +4698,7 @@
StringAppendF(&result, " %s (%d)\n", decodeColorMode(mode).c_str(), mode);
}
- ColorMode currentMode = display->getActiveColorMode();
+ ColorMode currentMode = display->getCompositionDisplay()->getState().colorMode;
StringAppendF(&result, " Current color mode: %s (%d)\n",
decodeColorMode(currentMode).c_str(), currentMode);
}
@@ -4691,18 +4734,21 @@
return layersProto;
}
-LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(const DisplayDevice& display) const {
+LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(const DisplayDevice& displayDevice) const {
LayersProto layersProto;
SizeProto* resolution = layersProto.mutable_resolution();
- resolution->set_w(display.getWidth());
- resolution->set_h(display.getHeight());
+ resolution->set_w(displayDevice.getWidth());
+ resolution->set_h(displayDevice.getHeight());
- layersProto.set_color_mode(decodeColorMode(display.getActiveColorMode()));
- layersProto.set_color_transform(decodeColorTransform(display.getColorTransform()));
- layersProto.set_global_transform(static_cast<int32_t>(display.getOrientationTransform()));
+ auto display = displayDevice.getCompositionDisplay();
+ const auto& displayState = display->getState();
- const auto displayId = display.getId();
+ layersProto.set_color_mode(decodeColorMode(displayState.colorMode));
+ layersProto.set_color_transform(decodeColorTransform(displayState.colorTransform));
+ layersProto.set_global_transform(displayState.orientation);
+
+ const auto displayId = displayDevice.getId();
LOG_ALWAYS_FATAL_IF(!displayId);
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(*displayId)) {
@@ -4823,7 +4869,8 @@
getRenderEngine().dump(result);
if (const auto display = getDefaultDisplayDeviceLocked()) {
- display->undefinedRegion.dump(result, "undefinedRegion");
+ display->getCompositionDisplay()->getState().undefinedRegion.dump(result,
+ "undefinedRegion");
StringAppendF(&result, " orientation=%d, isPoweredOn=%d\n", display->getOrientation(),
display->isPoweredOn());
}
@@ -5015,7 +5062,9 @@
case CREATE_CONNECTION:
case GET_COLOR_MANAGEMENT:
case GET_COMPOSITION_PREFERENCE:
- case GET_PROTECTED_CONTENT_SUPPORT: {
+ case GET_PROTECTED_CONTENT_SUPPORT:
+ case CACHE_BUFFER:
+ case UNCACHE_BUFFER: {
return OK;
}
case CAPTURE_LAYERS:
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a4bd3e9..499ebcd 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -47,6 +47,7 @@
#include <utils/threads.h>
#include "Barrier.h"
+#include "BufferStateLayerCache.h"
#include "DisplayDevice.h"
#include "DisplayHardware/HWC2.h"
#include "DisplayHardware/HWComposer.h"
@@ -99,6 +100,10 @@
class VSyncSource;
struct CompositionInfo;
+namespace compositionengine {
+class DisplaySurface;
+} // namespace compositionengine
+
namespace impl {
class EventThread;
} // namespace impl
@@ -414,7 +419,8 @@
void setTransactionState(const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
- const InputWindowCommands& inputWindowCommands) override;
+ const InputWindowCommands& inputWindowCommands,
+ int64_t desiredPresentTime) override;
void bootFinished() override;
bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& bufferProducer) const override;
@@ -460,6 +466,9 @@
uint64_t timestamp,
DisplayedFrameStats* outStats) const override;
status_t getProtectedContentSupport(bool* outSupported) const override;
+ status_t cacheBuffer(const sp<IBinder>& token, const sp<GraphicBuffer>& buffer,
+ int32_t* outBufferId) override;
+ status_t uncacheBuffer(const sp<IBinder>& token, int32_t bufferId) override;
/* ------------------------------------------------------------------------
* DeathRecipient interface
@@ -499,10 +508,6 @@
// called on the main thread in response to setPowerMode()
void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);
- // Called on the main thread in response to setActiveColorMode()
- void setActiveColorModeInternal(const sp<DisplayDevice>& display, ui::ColorMode colorMode,
- ui::Dataspace dataSpace, ui::RenderIntent renderIntent);
-
// Returns whether the transaction actually modified any state
bool handleMessageTransaction();
@@ -539,7 +544,8 @@
void latchAndReleaseBuffer(const sp<Layer>& layer);
void commitTransaction();
bool containsAnyInvalidClientState(const Vector<ComposerState>& states);
- bool composerStateContainsUnsignaledFences(const Vector<ComposerState>& states);
+ bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
+ const Vector<ComposerState>& states);
uint32_t setClientStateLocked(const ComposerState& composerState);
uint32_t setDisplayStateLocked(const DisplayState& s);
uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands);
@@ -737,11 +743,11 @@
/* ------------------------------------------------------------------------
* Display management
*/
- sp<DisplayDevice> setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
- const std::optional<DisplayId>& displayId,
- const DisplayDeviceState& state,
- const sp<DisplaySurface>& dispSurface,
- const sp<IGraphicBufferProducer>& producer);
+ sp<DisplayDevice> setupNewDisplayDeviceInternal(
+ const wp<IBinder>& displayToken, const std::optional<DisplayId>& displayId,
+ const DisplayDeviceState& state,
+ const sp<compositionengine::DisplaySurface>& dispSurface,
+ const sp<IGraphicBufferProducer>& producer);
void processDisplayChangesLocked();
void processDisplayHotplugEventsLocked();
@@ -989,12 +995,17 @@
};
struct TransactionState {
TransactionState(const Vector<ComposerState>& composerStates,
- const Vector<DisplayState>& displayStates, uint32_t transactionFlags)
- : states(composerStates), displays(displayStates), flags(transactionFlags) {}
+ const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
+ int64_t desiredPresentTime)
+ : states(composerStates),
+ displays(displayStates),
+ flags(transactionFlags),
+ time(desiredPresentTime) {}
Vector<ComposerState> states;
Vector<DisplayState> displays;
uint32_t flags;
+ int64_t time;
};
std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IBinderHash> mTransactionQueues;
@@ -1034,6 +1045,8 @@
sp<IInputFlinger> mInputFlinger;
InputWindowCommands mInputWindowCommands;
+
+ BufferStateLayerCache mBufferStateLayerCache;
};
}; // namespace android
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index e45af18..3ad6ec3 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -21,6 +21,7 @@
#include <android/frameworks/displayservice/1.0/IDisplayService.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
@@ -41,10 +42,14 @@
return OK;
}
- using android::hardware::graphics::allocator::V2_0::IAllocator;
+ status_t result = hardware::registerPassthroughServiceImplementation<
+ android::hardware::graphics::allocator::V3_0::IAllocator>();
+ if (result == OK) {
+ return OK;
+ }
- status_t result =
- hardware::registerPassthroughServiceImplementation<IAllocator>();
+ result = hardware::registerPassthroughServiceImplementation<
+ android::hardware::graphics::allocator::V2_0::IAllocator>();
if (result != OK) {
ALOGE("could not start graphics allocator service");
return result;
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 9339761..216532a 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -2323,6 +2323,143 @@
Transaction().setSidebandStream(layer, nullptr).apply();
}
+TEST_F(LayerTransactionTest, CacheBuffer_BufferState) {
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+
+ int32_t bufferId = -1;
+ ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
+ ASSERT_GE(bufferId, 0);
+
+ ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
+}
+
+TEST_F(LayerTransactionTest, CacheBuffers_BufferState) {
+ std::vector<int32_t> bufferIds;
+ int32_t bufferCount = 20;
+
+ for (int i = 0; i < bufferCount; i++) {
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ int32_t bufferId = -1;
+ ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
+ if (bufferId < 0) {
+ EXPECT_GE(bufferId, 0);
+ break;
+ }
+ bufferIds.push_back(bufferId);
+ }
+
+ for (int32_t bufferId : bufferIds) {
+ ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
+ }
+}
+
+TEST_F(LayerTransactionTest, CacheBufferInvalid_BufferState) {
+ sp<GraphicBuffer> buffer = nullptr;
+
+ int32_t bufferId = -1;
+ ASSERT_NE(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
+ ASSERT_LT(bufferId, 0);
+}
+
+TEST_F(LayerTransactionTest, UncacheBufferTwice_BufferState) {
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+
+ int32_t bufferId = -1;
+ ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
+ ASSERT_GE(bufferId, 0);
+
+ ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
+ mClient->uncacheBuffer(bufferId);
+}
+
+TEST_F(LayerTransactionTest, UncacheBufferInvalidId_BufferState) {
+ mClient->uncacheBuffer(-1);
+ mClient->uncacheBuffer(0);
+ mClient->uncacheBuffer(1);
+ mClient->uncacheBuffer(5);
+ mClient->uncacheBuffer(1000);
+}
+
+TEST_F(LayerTransactionTest, SetCachedBuffer_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ int32_t bufferId = -1;
+ ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId));
+ ASSERT_GE(bufferId, 0);
+
+ Transaction().setCachedBuffer(layer, bufferId).apply();
+
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+
+ ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
+}
+
+TEST_F(LayerTransactionTest, SetCachedBufferDelayed_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> cachedBuffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ int32_t bufferId = -1;
+ ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(cachedBuffer, &bufferId));
+ ASSERT_GE(bufferId, 0);
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::BLUE);
+ Transaction().setBuffer(layer, buffer).apply();
+ {
+ SCOPED_TRACE("Uncached buffer");
+
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ fillGraphicBufferColor(cachedBuffer, Rect(0, 0, 32, 32), Color::RED);
+ Transaction().setCachedBuffer(layer, bufferId).apply();
+ {
+ SCOPED_TRACE("Cached buffer");
+
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId));
+}
+
class ColorTransformHelper {
public:
static void DegammaColorSingle(half& s) {
@@ -2568,11 +2705,23 @@
}
}
+ void addExpectedPresentTime(nsecs_t expectedPresentTime) {
+ mExpectedPresentTime = expectedPresentTime;
+ }
+
void verifyTransactionStats(const TransactionStats& transactionStats) const {
const auto& [latchTime, presentFence, surfaceStats] = transactionStats;
if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) {
ASSERT_GE(latchTime, 0) << "bad latch time";
ASSERT_NE(presentFence, nullptr);
+ if (mExpectedPresentTime >= 0) {
+ ASSERT_EQ(presentFence->wait(3000), NO_ERROR);
+ ASSERT_GE(presentFence->getSignalTime(), mExpectedPresentTime - nsecs_t(5 * 1e6));
+ // if the panel is running at 30 hz, at the worst case, our expected time just
+ // misses vsync and we have to wait another 33.3ms
+ ASSERT_LE(presentFence->getSignalTime(),
+ mExpectedPresentTime + nsecs_t(66.666666 * 1e6));
+ }
} else {
ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented";
ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched";
@@ -2623,6 +2772,7 @@
}
};
ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
+ nsecs_t mExpectedPresentTime = -1;
std::unordered_map<sp<IBinder>, ExpectedSurfaceResult, IBinderHash> mExpectedSurfaceResults;
};
@@ -3272,6 +3422,143 @@
EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
}
+TEST_F(LayerCallbackTest, DesiredPresentTime) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the future
+ nsecs_t time = systemTime() + (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected.addExpectedPresentTime(time);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_Multiple) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback1;
+ int err = fillTransaction(transaction, &callback1, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the future
+ nsecs_t time = systemTime() + (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected1;
+ expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected1.addExpectedPresentTime(time);
+
+ CallbackHelper callback2;
+ err = fillTransaction(transaction, &callback2, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 33ms after the first frame
+ time += (33.3 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected2;
+ expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::ACQUIRED,
+ ExpectedResult::PreviousBuffer::RELEASED);
+ expected2.addExpectedPresentTime(time);
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_OutOfOrder) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback1;
+ int err = fillTransaction(transaction, &callback1, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the future
+ nsecs_t time = systemTime() + (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected1;
+ expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected1.addExpectedPresentTime(time);
+
+ CallbackHelper callback2;
+ err = fillTransaction(transaction, &callback2, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 33ms before the previous frame
+ time -= (33.3 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected2;
+ expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::ACQUIRED,
+ ExpectedResult::PreviousBuffer::RELEASED);
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_Past) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the past
+ nsecs_t time = systemTime() - (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected.addExpectedPresentTime(systemTime());
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
class LayerUpdateTest : public LayerTransactionTest {
protected:
virtual void SetUp() {
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index f63c911..ad31a40 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -46,7 +46,6 @@
"SchedulerUtilsTest.cpp",
"TimeStatsTest.cpp",
"mock/DisplayHardware/MockComposer.cpp",
- "mock/DisplayHardware/MockDisplaySurface.cpp",
"mock/DisplayHardware/MockPowerAdvisor.cpp",
"mock/gui/MockGraphicBufferConsumer.cpp",
"mock/gui/MockGraphicBufferProducer.cpp",
@@ -63,7 +62,6 @@
"libcompositionengine",
"libcompositionengine_mocks",
"librenderengine_mocks",
-
],
header_libs: [
"libsurfaceflinger_headers",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index e417350..e972785 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -17,6 +17,7 @@
#undef LOG_TAG
#define LOG_TAG "CompositionTest"
+#include <compositionengine/mock/DisplaySurface.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <gui/IProducerListener.h>
@@ -33,7 +34,6 @@
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
-#include "mock/DisplayHardware/MockDisplaySurface.h"
#include "mock/MockDispSync.h"
#include "mock/MockEventControlThread.h"
#include "mock/MockEventThread.h"
@@ -144,7 +144,8 @@
TestableSurfaceFlinger mFlinger;
sp<DisplayDevice> mDisplay;
sp<DisplayDevice> mExternalDisplay;
- sp<mock::DisplaySurface> mDisplaySurface = new mock::DisplaySurface();
+ sp<compositionengine::mock::DisplaySurface> mDisplaySurface =
+ new compositionengine::mock::DisplaySurface();
mock::NativeWindow* mNativeWindow = new mock::NativeWindow();
sp<GraphicBuffer> mBuffer = new GraphicBuffer();
@@ -326,11 +327,14 @@
}
static void setupHwcCompositionCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC)).Times(1);
+ EXPECT_CALL(*test->mDisplaySurface,
+ prepareFrame(compositionengine::DisplaySurface::COMPOSITION_HWC))
+ .Times(1);
}
static void setupRECompositionCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
+ EXPECT_CALL(*test->mDisplaySurface,
+ prepareFrame(compositionengine::DisplaySurface::COMPOSITION_GLES))
.Times(1);
EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
.WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index ff84a62..8201704 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -19,6 +19,9 @@
#include <type_traits>
+#include <compositionengine/Display.h>
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/mock/DisplaySurface.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <log/log.h>
@@ -28,7 +31,6 @@
#include "DisplayIdentificationTest.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
-#include "mock/DisplayHardware/MockDisplaySurface.h"
#include "mock/MockDispSync.h"
#include "mock/MockEventControlThread.h"
#include "mock/MockEventThread.h"
@@ -1152,8 +1154,10 @@
EXPECT_CALL(*mNativeWindow, perform(30)).Times(1);
auto displayDevice = mInjector.inject();
- displayDevice->getBestColorMode(mInputDataspace, mInputRenderIntent, &mOutDataspace,
- &mOutColorMode, &mOutRenderIntent);
+ displayDevice->getCompositionDisplay()
+ ->getDisplayColorProfile()
+ ->getBestColorMode(mInputDataspace, mInputRenderIntent, &mOutDataspace,
+ &mOutColorMode, &mOutRenderIntent);
}
ui::Dataspace mOutDataspace;
@@ -1227,7 +1231,8 @@
template <typename Case>
void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() {
const sp<BBinder> displayToken = new BBinder();
- const sp<mock::DisplaySurface> displaySurface = new mock::DisplaySurface();
+ const sp<compositionengine::mock::DisplaySurface> displaySurface =
+ new compositionengine::mock::DisplaySurface();
const sp<mock::GraphicBufferProducer> producer = new mock::GraphicBufferProducer();
// --------------------------------------------------------------------
@@ -1970,7 +1975,7 @@
// A display is set up
auto nativeWindow = new mock::NativeWindow();
- auto displaySurface = new mock::DisplaySurface();
+ auto displaySurface = new compositionengine::mock::DisplaySurface();
sp<GraphicBuffer> buf = new GraphicBuffer();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
@@ -2014,7 +2019,7 @@
// A display is set up
auto nativeWindow = new mock::NativeWindow();
- auto displaySurface = new mock::DisplaySurface();
+ auto displaySurface = new compositionengine::mock::DisplaySurface();
sp<GraphicBuffer> buf = new GraphicBuffer();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 15a8c5a..687941a 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -218,7 +218,7 @@
auto setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
const std::optional<DisplayId>& displayId,
const DisplayDeviceState& state,
- const sp<DisplaySurface>& dispSurface,
+ const sp<compositionengine::DisplaySurface>& dispSurface,
const sp<IGraphicBufferProducer>& producer) {
return mFlinger->setupNewDisplayDeviceInternal(displayToken, displayId, state, dispSurface,
producer);
@@ -492,7 +492,7 @@
return *this;
}
- auto& setDisplaySurface(const sp<DisplaySurface>& displaySurface) {
+ auto& setDisplaySurface(const sp<compositionengine::DisplaySurface>& displaySurface) {
mCreationArgs.displaySurface = displaySurface;
return *this;
}