1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <android/gui/IHdrConversionConstants.h>
18 #include <android_util_Binder.h>
19 #include <gui/SurfaceComposerClient.h>
20 #include <jni.h>
21 #include <nativehelper/ScopedPrimitiveArray.h>
22 #include <nativehelper/ScopedUtfChars.h>
23
24 namespace android {
25
nativeCreateDisplay(JNIEnv * env,jclass clazz,jstring nameObj,jboolean secure,jfloat requestedRefreshRate)26 static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj, jboolean secure,
27 jfloat requestedRefreshRate) {
28 ScopedUtfChars name(env, nameObj);
29 sp<IBinder> token(SurfaceComposerClient::createDisplay(String8(name.c_str()), bool(secure),
30 requestedRefreshRate));
31 return javaObjectForIBinder(env, token);
32 }
33
nativeDestroyDisplay(JNIEnv * env,jclass clazz,jobject tokenObj)34 static void nativeDestroyDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
35 sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
36 if (token == NULL) return;
37 SurfaceComposerClient::destroyDisplay(token);
38 }
39
nativeOverrideHdrTypes(JNIEnv * env,jclass clazz,jobject tokenObject,jintArray jHdrTypes)40 static void nativeOverrideHdrTypes(JNIEnv* env, jclass clazz, jobject tokenObject,
41 jintArray jHdrTypes) {
42 sp<IBinder> token(ibinderForJavaObject(env, tokenObject));
43 if (token == nullptr || jHdrTypes == nullptr) return;
44
45 ScopedIntArrayRO hdrTypes(env, jHdrTypes);
46 size_t numHdrTypes = hdrTypes.size();
47
48 std::vector<ui::Hdr> hdrTypesVector;
49 hdrTypesVector.reserve(numHdrTypes);
50 for (int i = 0; i < numHdrTypes; i++) {
51 hdrTypesVector.push_back(static_cast<ui::Hdr>(hdrTypes[i]));
52 }
53
54 status_t error = SurfaceComposerClient::overrideHdrTypes(token, hdrTypesVector);
55 if (error != NO_ERROR) {
56 jniThrowExceptionFmt(env, "java/lang/SecurityException",
57 "ACCESS_SURFACE_FLINGER is missing");
58 }
59 }
60
nativeSetHdrConversionMode(JNIEnv * env,jclass clazz,jint hdrConversionMode,jint preferredHdrOutputType,jintArray autoHdrOutputTypes,jint autoHdrOutputTypesLength)61 static int nativeSetHdrConversionMode(JNIEnv* env, jclass clazz, jint hdrConversionMode,
62 jint preferredHdrOutputType, jintArray autoHdrOutputTypes,
63 jint autoHdrOutputTypesLength) {
64 gui::HdrConversionStrategy hdrConversionStrategy;
65 switch (hdrConversionMode) {
66 case gui::IHdrConversionConstants::HdrConversionModePassthrough: {
67 hdrConversionStrategy.set<gui::HdrConversionStrategy::Tag::passthrough>(true);
68 break;
69 }
70 case gui::IHdrConversionConstants::HdrConversionModeAuto: {
71 jint* autoHdrOutputTypesArray = env->GetIntArrayElements(autoHdrOutputTypes, 0);
72 std::vector<int> autoHdrOutputTypesVector(autoHdrOutputTypesLength);
73 for (int i = 0; i < autoHdrOutputTypesLength; i++) {
74 autoHdrOutputTypesVector[i] = autoHdrOutputTypesArray[i];
75 }
76 hdrConversionStrategy.set<gui::HdrConversionStrategy::Tag::autoAllowedHdrTypes>(
77 autoHdrOutputTypesVector);
78 break;
79 }
80 case gui::IHdrConversionConstants::HdrConversionModeForce: {
81 hdrConversionStrategy.set<gui::HdrConversionStrategy::Tag::forceHdrConversion>(
82 preferredHdrOutputType);
83 break;
84 }
85 }
86 ui::Hdr prefHdrType;
87 SurfaceComposerClient::setHdrConversionStrategy(hdrConversionStrategy, &prefHdrType);
88 if (static_cast<jint>(prefHdrType) == 0) {
89 return -1;
90 } else {
91 return static_cast<jint>(prefHdrType);
92 }
93 }
94
nativeGetSupportedHdrOutputTypes(JNIEnv * env,jclass clazz)95 static jintArray nativeGetSupportedHdrOutputTypes(JNIEnv* env, jclass clazz) {
96 std::vector<gui::HdrConversionCapability> hdrConversionCapabilities;
97 SurfaceComposerClient::getHdrConversionCapabilities(&hdrConversionCapabilities);
98
99 // Extract unique HDR output types.
100 std::set<int> hdrOutputTypes;
101 for (const auto& hdrConversionCapability : hdrConversionCapabilities) {
102 // Filter out the value for SDR which is 0.
103 if (hdrConversionCapability.outputType > 0) {
104 hdrOutputTypes.insert(hdrConversionCapability.outputType);
105 }
106 }
107 jintArray array = env->NewIntArray(hdrOutputTypes.size());
108 if (array == nullptr) {
109 jniThrowException(env, "java/lang/OutOfMemoryError", nullptr);
110 return nullptr;
111 }
112 jint* arrayValues = env->GetIntArrayElements(array, 0);
113 size_t index = 0;
114 for (auto hdrOutputType : hdrOutputTypes) {
115 arrayValues[index++] = static_cast<jint>(hdrOutputType);
116 }
117 env->ReleaseIntArrayElements(array, arrayValues, 0);
118 return array;
119 }
120
nativeGetHdrOutputTypesWithLatency(JNIEnv * env,jclass clazz)121 static jintArray nativeGetHdrOutputTypesWithLatency(JNIEnv* env, jclass clazz) {
122 std::vector<gui::HdrConversionCapability> hdrConversionCapabilities;
123 SurfaceComposerClient::getHdrConversionCapabilities(&hdrConversionCapabilities);
124
125 // Extract unique HDR output types with latency.
126 std::set<int> hdrOutputTypes;
127 for (const auto& hdrConversionCapability : hdrConversionCapabilities) {
128 if (hdrConversionCapability.outputType > 0 && hdrConversionCapability.addsLatency) {
129 hdrOutputTypes.insert(hdrConversionCapability.outputType);
130 }
131 }
132 jintArray array = env->NewIntArray(hdrOutputTypes.size());
133 if (array == nullptr) {
134 jniThrowException(env, "java/lang/OutOfMemoryError", nullptr);
135 return nullptr;
136 }
137 jint* arrayValues = env->GetIntArrayElements(array, 0);
138 size_t index = 0;
139 for (auto hdrOutputType : hdrOutputTypes) {
140 arrayValues[index++] = static_cast<jint>(hdrOutputType);
141 }
142 env->ReleaseIntArrayElements(array, arrayValues, 0);
143 return array;
144 }
145
nativeGetHdrOutputConversionSupport(JNIEnv * env,jclass clazz)146 static jboolean nativeGetHdrOutputConversionSupport(JNIEnv* env, jclass clazz) {
147 bool isSupported;
148 status_t err = SurfaceComposerClient::getHdrOutputConversionSupport(&isSupported);
149 if (err == OK) {
150 return isSupported;
151 }
152 return JNI_FALSE;
153 }
154
nativeGetPhysicalDisplayIds(JNIEnv * env,jclass clazz)155 static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
156 const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
157 ScopedLongArrayRW values(env, env->NewLongArray(displayIds.size()));
158 if (values.get() == nullptr) {
159 jniThrowException(env, "java/lang/OutOfMemoryError", nullptr);
160 return nullptr;
161 }
162
163 for (size_t i = 0; i < displayIds.size(); ++i) {
164 values[i] = static_cast<jlong>(displayIds[i].value);
165 }
166
167 return values.getJavaArray();
168 }
169
nativeGetPhysicalDisplayToken(JNIEnv * env,jclass clazz,jlong physicalDisplayId)170 static jobject nativeGetPhysicalDisplayToken(JNIEnv* env, jclass clazz, jlong physicalDisplayId) {
171 const auto id = DisplayId::fromValue<PhysicalDisplayId>(physicalDisplayId);
172 if (!id) return nullptr;
173 sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(*id);
174 return javaObjectForIBinder(env, token);
175 }
176
177 // ----------------------------------------------------------------------------
178
179 static const JNINativeMethod sDisplayMethods[] = {
180 // clang-format off
181 {"nativeCreateDisplay", "(Ljava/lang/String;ZF)Landroid/os/IBinder;",
182 (void*)nativeCreateDisplay },
183 {"nativeDestroyDisplay", "(Landroid/os/IBinder;)V",
184 (void*)nativeDestroyDisplay },
185 {"nativeOverrideHdrTypes", "(Landroid/os/IBinder;[I)V",
186 (void*)nativeOverrideHdrTypes },
187 {"nativeGetPhysicalDisplayIds", "()[J",
188 (void*)nativeGetPhysicalDisplayIds },
189 {"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;",
190 (void*)nativeGetPhysicalDisplayToken },
191 {"nativeSetHdrConversionMode", "(II[II)I",
192 (void*)nativeSetHdrConversionMode },
193 {"nativeGetSupportedHdrOutputTypes", "()[I",
194 (void*)nativeGetSupportedHdrOutputTypes },
195 {"nativeGetHdrOutputTypesWithLatency", "()[I",
196 (void*)nativeGetHdrOutputTypesWithLatency },
197 {"nativeGetHdrOutputConversionSupport", "()Z",
198 (void*) nativeGetHdrOutputConversionSupport },
199 // clang-format on
200 };
201
register_com_android_server_display_DisplayControl(JNIEnv * env)202 int register_com_android_server_display_DisplayControl(JNIEnv* env) {
203 return jniRegisterNativeMethods(env, "com/android/server/display/DisplayControl",
204 sDisplayMethods, NELEM(sDisplayMethods));
205 }
206
207 } // namespace android
208