Merge "Adapt SurfaceControl to libgui API for display info"

This commit is contained in:
TreeHugger Robot
2020-02-03 22:29:43 +00:00
committed by Android (Google) Code Review
8 changed files with 304 additions and 340 deletions

View File

@@ -42,10 +42,10 @@
#include <android-base/properties.h>
#include <ui/DisplayConfig.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/DisplayInfo.h>
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
@@ -283,16 +283,19 @@ status_t BootAnimation::readyToRun() {
mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
if (mDisplayToken == nullptr)
return -1;
return NAME_NOT_FOUND;
DisplayInfo dinfo;
status_t status = SurfaceComposerClient::getDisplayInfo(mDisplayToken, &dinfo);
if (status)
return -1;
DisplayConfig displayConfig;
const status_t error =
SurfaceComposerClient::getActiveDisplayConfig(mDisplayToken, &displayConfig);
if (error != NO_ERROR)
return error;
const ui::Size& resolution = displayConfig.resolution;
// create the native surface
sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565);
SurfaceComposerClient::Transaction t;

View File

@@ -152,7 +152,8 @@ public final class SurfaceControl implements Parcelable {
int L, int T, int R, int B);
private static native void nativeSetDisplaySize(long transactionObj, IBinder displayToken,
int width, int height);
private static native SurfaceControl.PhysicalDisplayInfo[] nativeGetDisplayConfigs(
private static native SurfaceControl.DisplayInfo nativeGetDisplayInfo(IBinder displayToken);
private static native SurfaceControl.DisplayConfig[] nativeGetDisplayConfigs(
IBinder displayToken);
private static native DisplayedContentSamplingAttributes
nativeGetDisplayedContentSamplingAttributes(IBinder displayToken);
@@ -1278,140 +1279,45 @@ public final class SurfaceControl implements Parcelable {
Integer.toHexString(System.identityHashCode(this));
}
/*
* set display parameters.
* needs to be inside open/closeTransaction block
*/
/**
* Describes the properties of a physical display known to surface flinger.
* Immutable information about physical display.
*
* @hide
*/
public static final class PhysicalDisplayInfo {
/**
* @hide
*/
@UnsupportedAppUsage
public int width;
/**
* @hide
*/
@UnsupportedAppUsage
public int height;
/**
* @hide
*/
@UnsupportedAppUsage
public float refreshRate;
/**
* @hide
*/
@UnsupportedAppUsage
public static final class DisplayInfo {
public float density;
/**
* @hide
*/
@UnsupportedAppUsage
public float xDpi;
/**
* @hide
*/
@UnsupportedAppUsage
public float yDpi;
/**
* @hide
*/
@UnsupportedAppUsage
public boolean secure;
/**
* @hide
*/
@UnsupportedAppUsage
public long appVsyncOffsetNanos;
/**
* @hide
*/
@UnsupportedAppUsage
public long presentationDeadlineNanos;
/**
* @hide
*/
@UnsupportedAppUsage
public PhysicalDisplayInfo() {
}
/**
* @hide
*/
public PhysicalDisplayInfo(PhysicalDisplayInfo other) {
copyFrom(other);
}
/**
* @hide
*/
@Override
public boolean equals(Object o) {
return o instanceof PhysicalDisplayInfo && equals((PhysicalDisplayInfo)o);
}
/**
* @hide
*/
public boolean equals(PhysicalDisplayInfo other) {
return other != null
&& width == other.width
&& height == other.height
&& refreshRate == other.refreshRate
&& density == other.density
&& xDpi == other.xDpi
&& yDpi == other.yDpi
&& secure == other.secure
&& appVsyncOffsetNanos == other.appVsyncOffsetNanos
&& presentationDeadlineNanos == other.presentationDeadlineNanos;
}
/**
* @hide
*/
@Override
public int hashCode() {
return 0; // don't care
}
/**
* @hide
*/
public void copyFrom(PhysicalDisplayInfo other) {
width = other.width;
height = other.height;
refreshRate = other.refreshRate;
density = other.density;
xDpi = other.xDpi;
yDpi = other.yDpi;
secure = other.secure;
appVsyncOffsetNanos = other.appVsyncOffsetNanos;
presentationDeadlineNanos = other.presentationDeadlineNanos;
}
/**
* @hide
*/
@Override
public String toString() {
return "PhysicalDisplayInfo{" + width + " x " + height + ", " + refreshRate + " fps, "
+ "density " + density + ", " + xDpi + " x " + yDpi + " dpi, secure " + secure
+ ", appVsyncOffset " + appVsyncOffsetNanos
+ ", bufferDeadline " + presentationDeadlineNanos + "}";
return "DisplayInfo{density=" + density + ", secure=" + secure + "}";
}
}
/**
* Configuration supported by physical display.
*
* @hide
*/
public static final class DisplayConfig {
public int width;
public int height;
public float xDpi;
public float yDpi;
public float refreshRate;
public long appVsyncOffsetNanos;
public long presentationDeadlineNanos;
@Override
public String toString() {
return "DisplayConfig{width=" + width
+ ", height=" + height
+ ", xDpi=" + xDpi
+ ", yDpi=" + yDpi
+ ", refreshRate=" + refreshRate
+ ", appVsyncOffsetNanos=" + appVsyncOffsetNanos
+ ", presentationDeadlineNanos=" + presentationDeadlineNanos + "}";
}
}
@@ -1428,8 +1334,17 @@ public final class SurfaceControl implements Parcelable {
/**
* @hide
*/
@UnsupportedAppUsage
public static SurfaceControl.PhysicalDisplayInfo[] getDisplayConfigs(IBinder displayToken) {
public static SurfaceControl.DisplayInfo getDisplayInfo(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
return nativeGetDisplayInfo(displayToken);
}
/**
* @hide
*/
public static SurfaceControl.DisplayConfig[] getDisplayConfigs(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
@@ -1825,7 +1740,7 @@ public final class SurfaceControl implements Parcelable {
}
/**
* TODO(116025192): Remove this stopgap once framework is display-agnostic.
* TODO(b/116025192): Remove this stopgap once framework is display-agnostic.
*
* @hide
*/

View File

@@ -22,20 +22,22 @@
#include "android_hardware_input_InputWindowHandle.h"
#include "core_jni_helpers.h"
#include <memory>
#include <android-base/chrono_utils.h>
#include <android/graphics/region.h>
#include <android_runtime/AndroidRuntime.h>
#include <android-base/chrono_utils.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_view_SurfaceSession.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <jni.h>
#include <memory>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
#include <stdio.h>
#include <system/graphics.h>
#include <ui/ConfigStoreTypes.h>
#include <ui/DisplayConfig.h>
#include <ui/DisplayInfo.h>
#include <ui/DisplayedFrameStats.h>
#include <ui/FrameStats.h>
@@ -60,19 +62,24 @@ static void doThrowIAE(JNIEnv* env, const char* msg = nullptr) {
static const char* const OutOfResourcesException =
"android/view/Surface$OutOfResourcesException";
static struct {
jclass clazz;
jmethodID ctor;
jfieldID density;
jfieldID secure;
} gDisplayInfoClassInfo;
static struct {
jclass clazz;
jmethodID ctor;
jfieldID width;
jfieldID height;
jfieldID refreshRate;
jfieldID density;
jfieldID xDpi;
jfieldID yDpi;
jfieldID secure;
jfieldID refreshRate;
jfieldID appVsyncOffsetNanos;
jfieldID presentationDeadlineNanos;
} gPhysicalDisplayInfoClassInfo;
} gDisplayConfigClassInfo;
static struct {
jfieldID bottom;
@@ -766,37 +773,46 @@ static void nativeSetDisplaySize(JNIEnv* env, jclass clazz,
}
}
static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz,
jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return NULL;
Vector<DisplayInfo> configs;
if (SurfaceComposerClient::getDisplayConfigs(token, &configs) != NO_ERROR ||
configs.size() == 0) {
return NULL;
static jobject nativeGetDisplayInfo(JNIEnv* env, jclass clazz, jobject tokenObj) {
DisplayInfo info;
if (const auto token = ibinderForJavaObject(env, tokenObj);
!token || SurfaceComposerClient::getDisplayInfo(token, &info) != NO_ERROR) {
return nullptr;
}
jobjectArray configArray = env->NewObjectArray(configs.size(),
gPhysicalDisplayInfoClassInfo.clazz, NULL);
jobject object = env->NewObject(gDisplayInfoClassInfo.clazz, gDisplayInfoClassInfo.ctor);
env->SetFloatField(object, gDisplayInfoClassInfo.density, info.density);
env->SetBooleanField(object, gDisplayInfoClassInfo.secure, info.secure);
return object;
}
static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz, jobject tokenObj) {
Vector<DisplayConfig> configs;
if (const auto token = ibinderForJavaObject(env, tokenObj); !token ||
SurfaceComposerClient::getDisplayConfigs(token, &configs) != NO_ERROR ||
configs.isEmpty()) {
return nullptr;
}
jobjectArray configArray =
env->NewObjectArray(configs.size(), gDisplayConfigClassInfo.clazz, nullptr);
for (size_t c = 0; c < configs.size(); ++c) {
const DisplayInfo& info = configs[c];
jobject infoObj = env->NewObject(gPhysicalDisplayInfoClassInfo.clazz,
gPhysicalDisplayInfoClassInfo.ctor);
env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos,
info.appVsyncOffset);
env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos,
info.presentationDeadline);
env->SetObjectArrayElement(configArray, static_cast<jsize>(c), infoObj);
env->DeleteLocalRef(infoObj);
const DisplayConfig& config = configs[c];
jobject object =
env->NewObject(gDisplayConfigClassInfo.clazz, gDisplayConfigClassInfo.ctor);
env->SetIntField(object, gDisplayConfigClassInfo.width, config.resolution.getWidth());
env->SetIntField(object, gDisplayConfigClassInfo.height, config.resolution.getHeight());
env->SetFloatField(object, gDisplayConfigClassInfo.xDpi, config.xDpi);
env->SetFloatField(object, gDisplayConfigClassInfo.yDpi, config.yDpi);
env->SetFloatField(object, gDisplayConfigClassInfo.refreshRate, config.refreshRate);
env->SetLongField(object, gDisplayConfigClassInfo.appVsyncOffsetNanos,
config.appVsyncOffset);
env->SetLongField(object, gDisplayConfigClassInfo.presentationDeadlineNanos,
config.presentationDeadline);
env->SetObjectArrayElement(configArray, static_cast<jsize>(c), object);
env->DeleteLocalRef(object);
}
return configArray;
@@ -1409,7 +1425,9 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetDisplayProjection },
{"nativeSetDisplaySize", "(JLandroid/os/IBinder;II)V",
(void*)nativeSetDisplaySize },
{"nativeGetDisplayConfigs", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$PhysicalDisplayInfo;",
{"nativeGetDisplayInfo", "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DisplayInfo;",
(void*)nativeGetDisplayInfo },
{"nativeGetDisplayConfigs", "(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$DisplayConfig;",
(void*)nativeGetDisplayConfigs },
{"nativeGetActiveConfig", "(Landroid/os/IBinder;)I",
(void*)nativeGetActiveConfig },
@@ -1507,21 +1525,24 @@ int register_android_view_SurfaceControl(JNIEnv* env)
int err = RegisterMethodsOrDie(env, "android/view/SurfaceControl",
sSurfaceControlMethods, NELEM(sSurfaceControlMethods));
jclass clazz = FindClassOrDie(env, "android/view/SurfaceControl$PhysicalDisplayInfo");
gPhysicalDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
gPhysicalDisplayInfoClassInfo.ctor = GetMethodIDOrDie(env,
gPhysicalDisplayInfoClassInfo.clazz, "<init>", "()V");
gPhysicalDisplayInfoClassInfo.width = GetFieldIDOrDie(env, clazz, "width", "I");
gPhysicalDisplayInfoClassInfo.height = GetFieldIDOrDie(env, clazz, "height", "I");
gPhysicalDisplayInfoClassInfo.refreshRate = GetFieldIDOrDie(env, clazz, "refreshRate", "F");
gPhysicalDisplayInfoClassInfo.density = GetFieldIDOrDie(env, clazz, "density", "F");
gPhysicalDisplayInfoClassInfo.xDpi = GetFieldIDOrDie(env, clazz, "xDpi", "F");
gPhysicalDisplayInfoClassInfo.yDpi = GetFieldIDOrDie(env, clazz, "yDpi", "F");
gPhysicalDisplayInfoClassInfo.secure = GetFieldIDOrDie(env, clazz, "secure", "Z");
gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos = GetFieldIDOrDie(env,
clazz, "appVsyncOffsetNanos", "J");
gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos = GetFieldIDOrDie(env,
clazz, "presentationDeadlineNanos", "J");
jclass infoClazz = FindClassOrDie(env, "android/view/SurfaceControl$DisplayInfo");
gDisplayInfoClassInfo.clazz = MakeGlobalRefOrDie(env, infoClazz);
gDisplayInfoClassInfo.ctor = GetMethodIDOrDie(env, infoClazz, "<init>", "()V");
gDisplayInfoClassInfo.density = GetFieldIDOrDie(env, infoClazz, "density", "F");
gDisplayInfoClassInfo.secure = GetFieldIDOrDie(env, infoClazz, "secure", "Z");
jclass configClazz = FindClassOrDie(env, "android/view/SurfaceControl$DisplayConfig");
gDisplayConfigClassInfo.clazz = MakeGlobalRefOrDie(env, configClazz);
gDisplayConfigClassInfo.ctor = GetMethodIDOrDie(env, configClazz, "<init>", "()V");
gDisplayConfigClassInfo.width = GetFieldIDOrDie(env, configClazz, "width", "I");
gDisplayConfigClassInfo.height = GetFieldIDOrDie(env, configClazz, "height", "I");
gDisplayConfigClassInfo.xDpi = GetFieldIDOrDie(env, configClazz, "xDpi", "F");
gDisplayConfigClassInfo.yDpi = GetFieldIDOrDie(env, configClazz, "yDpi", "F");
gDisplayConfigClassInfo.refreshRate = GetFieldIDOrDie(env, configClazz, "refreshRate", "F");
gDisplayConfigClassInfo.appVsyncOffsetNanos =
GetFieldIDOrDie(env, configClazz, "appVsyncOffsetNanos", "J");
gDisplayConfigClassInfo.presentationDeadlineNanos =
GetFieldIDOrDie(env, configClazz, "presentationDeadlineNanos", "J");
jclass rectClazz = FindClassOrDie(env, "android/graphics/Rect");
gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClazz, "bottom", "I");

View File

@@ -22,43 +22,50 @@ namespace android {
namespace uirenderer {
namespace test {
static const int IDENT_DISPLAYEVENT = 1;
static android::DisplayInfo DUMMY_DISPLAY{
1080, // w
1920, // h
320.0, // xdpi
320.0, // ydpi
60.0, // fps
2.0, // density
ui::ROTATION_0, // orientation
false, // secure?
0, // appVsyncOffset
0, // presentationDeadline
};
DisplayInfo getInternalDisplay() {
#if !HWUI_NULL_GPU
DisplayInfo display;
const sp<IBinder> token = SurfaceComposerClient::getInternalDisplayToken();
LOG_ALWAYS_FATAL_IF(token == nullptr,
"Failed to get display info because internal display is disconnected\n");
status_t status = SurfaceComposerClient::getDisplayInfo(token, &display);
LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n");
return display;
const DisplayInfo& getDisplayInfo() {
static DisplayInfo info = [] {
DisplayInfo info;
#if HWUI_NULL_GPU
info.density = 2.f;
#else
return DUMMY_DISPLAY;
const sp<IBinder> token = SurfaceComposerClient::getInternalDisplayToken();
LOG_ALWAYS_FATAL_IF(!token, "%s: No internal display", __FUNCTION__);
const status_t status = SurfaceComposerClient::getDisplayInfo(token, &info);
LOG_ALWAYS_FATAL_IF(status, "%s: Failed to get display info", __FUNCTION__);
#endif
return info;
}();
return info;
}
// Initialize to a dummy default
android::DisplayInfo gDisplay = DUMMY_DISPLAY;
const DisplayConfig& getActiveDisplayConfig() {
static DisplayConfig config = [] {
DisplayConfig config;
#if HWUI_NULL_GPU
config.resolution = ui::Size(1080, 1920);
config.xDpi = config.yDpi = 320.f;
config.refreshRate = 60.f;
#else
const sp<IBinder> token = SurfaceComposerClient::getInternalDisplayToken();
LOG_ALWAYS_FATAL_IF(!token, "%s: No internal display", __FUNCTION__);
const status_t status = SurfaceComposerClient::getActiveDisplayConfig(token, &config);
LOG_ALWAYS_FATAL_IF(status, "%s: Failed to get active display config", __FUNCTION__);
#endif
return config;
}();
return config;
}
TestContext::TestContext() {
mLooper = new Looper(true);
mSurfaceComposerClient = new SurfaceComposerClient();
mLooper->addFd(mDisplayEventReceiver.getFd(), IDENT_DISPLAYEVENT, Looper::EVENT_INPUT, nullptr,
nullptr);
constexpr int EVENT_ID = 1;
mLooper->addFd(mDisplayEventReceiver.getFd(), EVENT_ID, Looper::EVENT_INPUT, nullptr, nullptr);
}
TestContext::~TestContext() {}
@@ -79,8 +86,10 @@ void TestContext::createSurface() {
}
void TestContext::createWindowSurface() {
mSurfaceControl = mSurfaceComposerClient->createSurface(String8("HwuiTest"), gDisplay.w,
gDisplay.h, PIXEL_FORMAT_RGBX_8888);
const ui::Size& resolution = getActiveDisplayResolution();
mSurfaceControl =
mSurfaceComposerClient->createSurface(String8("HwuiTest"), resolution.getWidth(),
resolution.getHeight(), PIXEL_FORMAT_RGBX_8888);
SurfaceComposerClient::Transaction t;
t.setLayer(mSurfaceControl, 0x7FFFFFF).show(mSurfaceControl).apply();
@@ -94,7 +103,8 @@ void TestContext::createOffscreenSurface() {
producer->setMaxDequeuedBufferCount(3);
producer->setAsyncMode(true);
mConsumer = new BufferItemConsumer(consumer, GRALLOC_USAGE_HW_COMPOSER, 4);
mConsumer->setDefaultBufferSize(gDisplay.w, gDisplay.h);
const ui::Size& resolution = getActiveDisplayResolution();
mConsumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight());
mSurface = new Surface(producer);
}

View File

@@ -23,20 +23,25 @@
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceControl.h>
#include <ui/DisplayConfig.h>
#include <ui/DisplayInfo.h>
#include <utils/Looper.h>
#include <atomic>
#include <thread>
#define dp(x) ((x) * android::uirenderer::test::getDisplayInfo().density)
namespace android {
namespace uirenderer {
namespace test {
extern DisplayInfo gDisplay;
#define dp(x) ((x)*android::uirenderer::test::gDisplay.density)
const DisplayInfo& getDisplayInfo();
const DisplayConfig& getActiveDisplayConfig();
DisplayInfo getInternalDisplay();
inline const ui::Size& getActiveDisplayResolution() {
return getActiveDisplayConfig().resolution;
}
class TestContext {
public:

View File

@@ -109,16 +109,14 @@ void outputBenchmarkReport(const TestScene::Info& info, const TestScene::Options
void run(const TestScene::Info& info, const TestScene::Options& opts,
benchmark::BenchmarkReporter* reporter) {
// Switch to the real display
gDisplay = getInternalDisplay();
Properties::forceDrawFrame = true;
TestContext testContext;
testContext.setRenderOffscreen(opts.renderOffscreen);
// create the native surface
const int width = gDisplay.w;
const int height = gDisplay.h;
const ui::Size& resolution = getActiveDisplayResolution();
const int width = resolution.getWidth();
const int height = resolution.getHeight();
sp<Surface> surface = testContext.surface();
std::unique_ptr<TestScene> scene(info.createScene(opts));

View File

@@ -91,8 +91,12 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private void tryConnectDisplayLocked(long physicalDisplayId) {
final IBinder displayToken = SurfaceControl.getPhysicalDisplayToken(physicalDisplayId);
if (displayToken != null) {
SurfaceControl.PhysicalDisplayInfo[] configs =
SurfaceControl.getDisplayConfigs(displayToken);
SurfaceControl.DisplayInfo info = SurfaceControl.getDisplayInfo(displayToken);
if (info == null) {
Slog.w(TAG, "No valid info found for display device " + physicalDisplayId);
return;
}
SurfaceControl.DisplayConfig[] configs = SurfaceControl.getDisplayConfigs(displayToken);
if (configs == null) {
// There are no valid configs for this device, so we can't use it
Slog.w(TAG, "No valid configs found for display device " + physicalDisplayId);
@@ -115,19 +119,19 @@ final class LocalDisplayAdapter extends DisplayAdapter {
activeColorMode = Display.COLOR_MODE_INVALID;
}
int[] colorModes = SurfaceControl.getDisplayColorModes(displayToken);
SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs =
SurfaceControl.DesiredDisplayConfigSpecs configSpecs =
SurfaceControl.getDesiredDisplayConfigSpecs(displayToken);
LocalDisplayDevice device = mDevices.get(physicalDisplayId);
if (device == null) {
// Display was added.
final boolean isInternal = mDevices.size() == 0;
device = new LocalDisplayDevice(displayToken, physicalDisplayId, configs,
activeConfig, desiredDisplayConfigSpecs, colorModes, activeColorMode,
device = new LocalDisplayDevice(displayToken, physicalDisplayId, info,
configs, activeConfig, configSpecs, colorModes, activeColorMode,
isInternal);
mDevices.put(physicalDisplayId, device);
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
} else if (device.updatePhysicalDisplayInfoLocked(configs, activeConfig,
desiredDisplayConfigSpecs, colorModes, activeColorMode)) {
} else if (device.updateDisplayConfigsLocked(configs, activeConfig, configSpecs,
colorModes, activeColorMode)) {
// Display properties changed.
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
}
@@ -179,7 +183,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private DisplayModeDirector.DesiredDisplayModeSpecs mDisplayModeSpecs =
new DisplayModeDirector.DesiredDisplayModeSpecs();
private boolean mDisplayModeSpecsInvalid;
private int mActivePhysIndex;
private int mActiveConfigId;
private int mActiveColorMode;
private boolean mActiveColorModeInvalid;
private Display.HdrCapabilities mHdrCapabilities;
@@ -189,21 +193,25 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private boolean mGameContentTypeRequested;
private boolean mSidekickActive;
private SidekickInternal mSidekickInternal;
private SurfaceControl.PhysicalDisplayInfo[] mDisplayInfos;
private SurfaceControl.DisplayInfo mDisplayInfo;
private SurfaceControl.DisplayConfig[] mDisplayConfigs;
private Spline mSystemBrightnessToNits;
private Spline mNitsToHalBrightness;
private boolean mHalBrightnessSupport;
LocalDisplayDevice(IBinder displayToken, long physicalDisplayId,
SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo,
SurfaceControl.DesiredDisplayConfigSpecs physicalDisplayConfigSpecs,
SurfaceControl.DisplayInfo info, SurfaceControl.DisplayConfig[] configs,
int activeConfigId, SurfaceControl.DesiredDisplayConfigSpecs configSpecs,
int[] colorModes, int activeColorMode, boolean isInternal) {
super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + physicalDisplayId);
mPhysicalDisplayId = physicalDisplayId;
mIsInternal = isInternal;
updatePhysicalDisplayInfoLocked(physicalDisplayInfos, activeDisplayInfo,
physicalDisplayConfigSpecs, colorModes, activeColorMode);
mDisplayInfo = info;
updateDisplayConfigsLocked(configs, activeConfigId, configSpecs, colorModes,
activeColorMode);
updateColorModesLocked(colorModes, activeColorMode);
mSidekickInternal = LocalServices.getService(SidekickInternal.class);
if (mIsInternal) {
LightsManager lights = LocalServices.getService(LightsManager.class);
@@ -226,23 +234,24 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return true;
}
public boolean updatePhysicalDisplayInfoLocked(
SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo,
SurfaceControl.DesiredDisplayConfigSpecs physicalDisplayConfigSpecs,
int[] colorModes, int activeColorMode) {
mDisplayInfos = Arrays.copyOf(physicalDisplayInfos, physicalDisplayInfos.length);
mActivePhysIndex = activeDisplayInfo;
public boolean updateDisplayConfigsLocked(
SurfaceControl.DisplayConfig[] configs, int activeConfigId,
SurfaceControl.DesiredDisplayConfigSpecs configSpecs, int[] colorModes,
int activeColorMode) {
mDisplayConfigs = Arrays.copyOf(configs, configs.length);
mActiveConfigId = activeConfigId;
// Build an updated list of all existing modes.
ArrayList<DisplayModeRecord> records = new ArrayList<DisplayModeRecord>();
boolean modesAdded = false;
for (int i = 0; i < physicalDisplayInfos.length; i++) {
SurfaceControl.PhysicalDisplayInfo info = physicalDisplayInfos[i];
for (int i = 0; i < configs.length; i++) {
SurfaceControl.DisplayConfig config = configs[i];
// First, check to see if we've already added a matching mode. Since not all
// configuration options are exposed via Display.Mode, it's possible that we have
// multiple PhysicalDisplayInfos that would generate the same Display.Mode.
// multiple DisplayConfigs that would generate the same Display.Mode.
boolean existingMode = false;
for (int j = 0; j < records.size(); j++) {
if (records.get(j).hasMatchingMode(info)) {
if (records.get(j).hasMatchingMode(config)) {
existingMode = true;
break;
}
@@ -253,9 +262,9 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// If we haven't already added a mode for this configuration to the new set of
// supported modes then check to see if we have one in the prior set of supported
// modes to reuse.
DisplayModeRecord record = findDisplayModeRecord(info);
DisplayModeRecord record = findDisplayModeRecord(config);
if (record == null) {
record = new DisplayModeRecord(info);
record = new DisplayModeRecord(config);
modesAdded = true;
}
records.add(record);
@@ -265,7 +274,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
DisplayModeRecord activeRecord = null;
for (int i = 0; i < records.size(); i++) {
DisplayModeRecord record = records.get(i);
if (record.hasMatchingMode(physicalDisplayInfos[activeDisplayInfo])){
if (record.hasMatchingMode(configs[activeConfigId])) {
activeRecord = record;
break;
}
@@ -282,17 +291,15 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// Check whether surface flinger spontaneously changed display config specs out from
// under us. If so, schedule a traversal to reapply our display config specs.
if (mDisplayModeSpecs.baseModeId != 0) {
int activeBaseMode =
findMatchingModeIdLocked(physicalDisplayConfigSpecs.defaultConfig);
int activeBaseMode = findMatchingModeIdLocked(configSpecs.defaultConfig);
// If we can't map the defaultConfig index to a mode, then the physical display
// configs must have changed, and the code below for handling changes to the
// list of available modes will take care of updating display config specs.
if (activeBaseMode != 0) {
if (mDisplayModeSpecs.baseModeId != activeBaseMode
|| mDisplayModeSpecs.refreshRateRange.min
!= physicalDisplayConfigSpecs.minRefreshRate
|| mDisplayModeSpecs.refreshRateRange.min != configSpecs.minRefreshRate
|| mDisplayModeSpecs.refreshRateRange.max
!= physicalDisplayConfigSpecs.maxRefreshRate) {
!= configSpecs.maxRefreshRate) {
mDisplayModeSpecsInvalid = true;
sendTraversalRequestLocked();
}
@@ -313,7 +320,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
// Update the default mode, if needed.
if (findDisplayInfoIndexLocked(mDefaultModeId) < 0) {
if (findDisplayConfigIdLocked(mDefaultModeId) < 0) {
if (mDefaultModeId != 0) {
Slog.w(TAG, "Default display mode no longer available, using currently"
+ " active mode as default.");
@@ -434,10 +441,10 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return true;
}
private DisplayModeRecord findDisplayModeRecord(SurfaceControl.PhysicalDisplayInfo info) {
private DisplayModeRecord findDisplayModeRecord(SurfaceControl.DisplayConfig config) {
for (int i = 0; i < mSupportedModes.size(); i++) {
DisplayModeRecord record = mSupportedModes.valueAt(i);
if (record.hasMatchingMode(info)) {
if (record.hasMatchingMode(config)) {
return record;
}
}
@@ -455,10 +462,10 @@ final class LocalDisplayAdapter extends DisplayAdapter {
@Override
public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
if (mInfo == null) {
SurfaceControl.PhysicalDisplayInfo phys = mDisplayInfos[mActivePhysIndex];
SurfaceControl.DisplayConfig config = mDisplayConfigs[mActiveConfigId];
mInfo = new DisplayDeviceInfo();
mInfo.width = phys.width;
mInfo.height = phys.height;
mInfo.width = config.width;
mInfo.height = config.height;
mInfo.modeId = mActiveModeId;
mInfo.defaultModeId = mDefaultModeId;
mInfo.supportedModes = getDisplayModes(mSupportedModes);
@@ -471,20 +478,20 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mInfo.supportedColorModes[i] = mSupportedColorModes.get(i);
}
mInfo.hdrCapabilities = mHdrCapabilities;
mInfo.appVsyncOffsetNanos = phys.appVsyncOffsetNanos;
mInfo.presentationDeadlineNanos = phys.presentationDeadlineNanos;
mInfo.appVsyncOffsetNanos = config.appVsyncOffsetNanos;
mInfo.presentationDeadlineNanos = config.presentationDeadlineNanos;
mInfo.state = mState;
mInfo.uniqueId = getUniqueId();
final DisplayAddress.Physical physicalAddress =
DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId);
mInfo.address = physicalAddress;
mInfo.densityDpi = (int) (phys.density * 160 + 0.5f);
mInfo.xDpi = phys.xDpi;
mInfo.yDpi = phys.yDpi;
mInfo.densityDpi = (int) (mDisplayInfo.density * 160 + 0.5f);
mInfo.xDpi = config.xDpi;
mInfo.yDpi = config.yDpi;
// Assume that all built-in displays that have secure output (eg. HDCP) also
// support compositing from gralloc protected buffers.
if (phys.secure) {
if (mDisplayInfo.secure) {
mInfo.flags = DisplayDeviceInfo.FLAG_SECURE
| DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS;
}
@@ -721,8 +728,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// a valid mode.
return;
}
int basePhysIndex = findDisplayInfoIndexLocked(displayModeSpecs.baseModeId);
if (basePhysIndex < 0) {
int baseConfigId = findDisplayConfigIdLocked(displayModeSpecs.baseModeId);
if (baseConfigId < 0) {
// When a display is hotplugged, it's possible for a mode to be removed that was
// previously valid. Because of the way display changes are propagated through the
// framework, and the caching of the display mode specs in LogicalDisplay, it's
@@ -740,7 +747,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
getHandler().sendMessage(PooledLambda.obtainMessage(
LocalDisplayDevice::setDesiredDisplayModeSpecsAsync, this,
getDisplayTokenLocked(),
new SurfaceControl.DesiredDisplayConfigSpecs(basePhysIndex,
new SurfaceControl.DesiredDisplayConfigSpecs(baseConfigId,
mDisplayModeSpecs.refreshRateRange.min,
mDisplayModeSpecs.refreshRateRange.max)));
}
@@ -764,22 +771,22 @@ final class LocalDisplayAdapter extends DisplayAdapter {
updateDeviceInfoLocked();
}
public void onActivePhysicalDisplayModeChangedLocked(int physIndex) {
if (updateActiveModeLocked(physIndex)) {
public void onActiveDisplayConfigChangedLocked(int configId) {
if (updateActiveModeLocked(configId)) {
updateDeviceInfoLocked();
}
}
public boolean updateActiveModeLocked(int activePhysIndex) {
if (mActivePhysIndex == activePhysIndex) {
public boolean updateActiveModeLocked(int activeConfigId) {
if (mActiveConfigId == activeConfigId) {
return false;
}
mActivePhysIndex = activePhysIndex;
mActiveModeId = findMatchingModeIdLocked(activePhysIndex);
mActiveConfigId = activeConfigId;
mActiveModeId = findMatchingModeIdLocked(activeConfigId);
mActiveModeInvalid = mActiveModeId == 0;
if (mActiveModeInvalid) {
Slog.w(TAG, "In unknown mode after setting allowed configs"
+ ", activePhysIndex=" + mActivePhysIndex);
+ ", activeConfigId=" + mActiveConfigId);
}
return true;
}
@@ -850,7 +857,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
pw.println("mPhysicalDisplayId=" + mPhysicalDisplayId);
pw.println("mDisplayModeSpecs={" + mDisplayModeSpecs + "}");
pw.println("mDisplayModeSpecsInvalid=" + mDisplayModeSpecsInvalid);
pw.println("mActivePhysIndex=" + mActivePhysIndex);
pw.println("mActiveConfigId=" + mActiveConfigId);
pw.println("mActiveModeId=" + mActiveModeId);
pw.println("mActiveColorMode=" + mActiveColorMode);
pw.println("mDefaultModeId=" + mDefaultModeId);
@@ -861,9 +868,10 @@ final class LocalDisplayAdapter extends DisplayAdapter {
pw.println("mAllmRequested=" + mAllmRequested);
pw.println("mGameContentTypeSupported" + mGameContentTypeSupported);
pw.println("mGameContentTypeRequested" + mGameContentTypeRequested);
pw.println("mDisplayInfos=");
for (int i = 0; i < mDisplayInfos.length; i++) {
pw.println(" " + mDisplayInfos[i]);
pw.println("mDisplayInfo=" + mDisplayInfo);
pw.println("mDisplayConfigs=");
for (int i = 0; i < mDisplayConfigs.length; i++) {
pw.println(" " + mDisplayConfigs[i]);
}
pw.println("mSupportedModes=");
for (int i = 0; i < mSupportedModes.size(); i++) {
@@ -879,12 +887,12 @@ final class LocalDisplayAdapter extends DisplayAdapter {
pw.println("]");
}
private int findDisplayInfoIndexLocked(int modeId) {
private int findDisplayConfigIdLocked(int modeId) {
DisplayModeRecord record = mSupportedModes.get(modeId);
if (record != null) {
for (int i = 0; i < mDisplayInfos.length; i++) {
SurfaceControl.PhysicalDisplayInfo info = mDisplayInfos[i];
if (record.hasMatchingMode(info)){
for (int i = 0; i < mDisplayConfigs.length; i++) {
SurfaceControl.DisplayConfig config = mDisplayConfigs[i];
if (record.hasMatchingMode(config)) {
return i;
}
}
@@ -892,11 +900,11 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return -1;
}
private int findMatchingModeIdLocked(int physIndex) {
SurfaceControl.PhysicalDisplayInfo info = mDisplayInfos[physIndex];
private int findMatchingModeIdLocked(int configId) {
SurfaceControl.DisplayConfig config = mDisplayConfigs[configId];
for (int i = 0; i < mSupportedModes.size(); i++) {
DisplayModeRecord record = mSupportedModes.valueAt(i);
if (record.hasMatchingMode(info)) {
if (record.hasMatchingMode(config)) {
return record.mMode.getModeId();
}
}
@@ -948,23 +956,23 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private static final class DisplayModeRecord {
public final Display.Mode mMode;
public DisplayModeRecord(SurfaceControl.PhysicalDisplayInfo phys) {
mMode = createMode(phys.width, phys.height, phys.refreshRate);
DisplayModeRecord(SurfaceControl.DisplayConfig config) {
mMode = createMode(config.width, config.height, config.refreshRate);
}
/**
* Returns whether the mode generated by the given PhysicalDisplayInfo matches the mode
* Returns whether the mode generated by the given DisplayConfig matches the mode
* contained by the record modulo mode ID.
*
* Note that this doesn't necessarily mean the the PhysicalDisplayInfos are identical, just
* Note that this doesn't necessarily mean that the DisplayConfigs are identical, just
* that they generate identical modes.
*/
public boolean hasMatchingMode(SurfaceControl.PhysicalDisplayInfo info) {
public boolean hasMatchingMode(SurfaceControl.DisplayConfig config) {
int modeRefreshRate = Float.floatToIntBits(mMode.getRefreshRate());
int displayInfoRefreshRate = Float.floatToIntBits(info.refreshRate);
return mMode.getPhysicalWidth() == info.width
&& mMode.getPhysicalHeight() == info.height
&& modeRefreshRate == displayInfoRefreshRate;
int configRefreshRate = Float.floatToIntBits(config.refreshRate);
return mMode.getPhysicalWidth() == config.width
&& mMode.getPhysicalHeight() == config.height
&& modeRefreshRate == configRefreshRate;
}
public String toString() {
@@ -989,12 +997,12 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
@Override
public void onConfigChanged(long timestampNanos, long physicalDisplayId, int physIndex) {
public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
if (DEBUG) {
Slog.d(TAG, "onConfigChanged("
+ "timestampNanos=" + timestampNanos
+ ", physicalDisplayId=" + physicalDisplayId
+ ", physIndex=" + physIndex + ")");
+ ", configId=" + configId + ")");
}
synchronized (getSyncRoot()) {
LocalDisplayDevice device = mDevices.get(physicalDisplayId);
@@ -1005,7 +1013,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
return;
}
device.onActivePhysicalDisplayModeChangedLocked(physIndex);
device.onActiveDisplayConfigChangedLocked(configId);
}
}
}

View File

@@ -109,10 +109,11 @@ public class LocalDisplayAdapterTest {
*/
@Test
public void testPrivateDisplay() throws Exception {
setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_A), createDummyDisplayInfo()));
setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_B), createDummyDisplayInfo()));
setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_C), createDummyDisplayInfo()));
setUpDisplay(new FakeDisplay(PORT_A));
setUpDisplay(new FakeDisplay(PORT_B));
setUpDisplay(new FakeDisplay(PORT_C));
updateAvailableDisplays();
doReturn(new int[]{ PORT_B }).when(mMockedResources)
.getIntArray(com.android.internal.R.array.config_localPrivateDisplayPorts);
mAdapter.registerLocked();
@@ -135,9 +136,10 @@ public class LocalDisplayAdapterTest {
*/
@Test
public void testPublicDisplaysForNoConfigLocalPrivateDisplayPorts() throws Exception {
setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_A), createDummyDisplayInfo()));
setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_C), createDummyDisplayInfo()));
setUpDisplay(new FakeDisplay(PORT_A));
setUpDisplay(new FakeDisplay(PORT_C));
updateAvailableDisplays();
// config_localPrivateDisplayPorts is null
mAdapter.registerLocked();
@@ -165,9 +167,8 @@ public class LocalDisplayAdapterTest {
*/
@Test
public void testDpiValues() throws Exception {
// needs default one always
setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_A), createDummyDisplayInfo()));
setUpDisplay(new DisplayConfig(createDisplayAddress(PORT_B), createDummyDisplayInfo()));
setUpDisplay(new FakeDisplay(PORT_A));
setUpDisplay(new FakeDisplay(PORT_B));
updateAvailableDisplays();
mAdapter.registerLocked();
@@ -193,32 +194,32 @@ public class LocalDisplayAdapterTest {
assertEquals(expectedDensityDpi, info.densityDpi);
}
private class DisplayConfig {
private static class FakeDisplay {
public final DisplayAddress.Physical address;
public final IBinder displayToken = new Binder();
public final SurfaceControl.PhysicalDisplayInfo displayInfo;
public final IBinder token = new Binder();
public final SurfaceControl.DisplayInfo info;
public final SurfaceControl.DisplayConfig config;
private DisplayConfig(
DisplayAddress.Physical address, SurfaceControl.PhysicalDisplayInfo displayInfo) {
this.address = address;
this.displayInfo = displayInfo;
private FakeDisplay(int port) {
this.address = createDisplayAddress(port);
this.info = createFakeDisplayInfo();
this.config = createFakeDisplayConfig();
}
}
private void setUpDisplay(DisplayConfig config) {
mAddresses.add(config.address);
doReturn(config.displayToken).when(() ->
SurfaceControl.getPhysicalDisplayToken(config.address.getPhysicalDisplayId()));
doReturn(new SurfaceControl.PhysicalDisplayInfo[]{
config.displayInfo
}).when(() -> SurfaceControl.getDisplayConfigs(config.displayToken));
doReturn(0).when(() -> SurfaceControl.getActiveConfig(config.displayToken));
doReturn(0).when(() -> SurfaceControl.getActiveColorMode(config.displayToken));
doReturn(new int[]{
0
}).when(() -> SurfaceControl.getDisplayColorModes(config.displayToken));
private void setUpDisplay(FakeDisplay display) {
mAddresses.add(display.address);
doReturn(display.token).when(() ->
SurfaceControl.getPhysicalDisplayToken(display.address.getPhysicalDisplayId()));
doReturn(display.info).when(() -> SurfaceControl.getDisplayInfo(display.token));
doReturn(new SurfaceControl.DisplayConfig[] { display.config }).when(
() -> SurfaceControl.getDisplayConfigs(display.token));
doReturn(0).when(() -> SurfaceControl.getActiveConfig(display.token));
doReturn(0).when(() -> SurfaceControl.getActiveColorMode(display.token));
doReturn(new int[] { 0 }).when(
() -> SurfaceControl.getDisplayColorModes(display.token));
doReturn(new SurfaceControl.DesiredDisplayConfigSpecs(0, 60.f, 60.f))
.when(() -> SurfaceControl.getDesiredDisplayConfigSpecs(config.displayToken));
.when(() -> SurfaceControl.getDesiredDisplayConfigSpecs(display.token));
}
private void updateAvailableDisplays() {
@@ -235,18 +236,21 @@ public class LocalDisplayAdapterTest {
return DisplayAddress.fromPortAndModel((byte) port, DISPLAY_MODEL);
}
private static SurfaceControl.PhysicalDisplayInfo createDummyDisplayInfo() {
SurfaceControl.PhysicalDisplayInfo info = new SurfaceControl.PhysicalDisplayInfo();
private static SurfaceControl.DisplayInfo createFakeDisplayInfo() {
final SurfaceControl.DisplayInfo info = new SurfaceControl.DisplayInfo();
info.density = 100;
info.xDpi = 100;
info.yDpi = 100;
info.secure = false;
info.width = 800;
info.height = 600;
return info;
}
private static SurfaceControl.DisplayConfig createFakeDisplayConfig() {
final SurfaceControl.DisplayConfig config = new SurfaceControl.DisplayConfig();
config.width = 800;
config.height = 600;
config.xDpi = 100;
config.yDpi = 100;
return config;
}
private void waitForHandlerToComplete(Handler handler, long waitTimeMs)
throws InterruptedException {
final Object lock = new Object();