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
nativeCreateVirtualDisplay(JNIEnv * env,jclass clazz,jstring nameObj,jboolean secure,jstring uniqueIdStr,jfloat requestedRefreshRate)26 static jobject nativeCreateVirtualDisplay(JNIEnv* env, jclass clazz, jstring nameObj,
27 jboolean secure, jstring uniqueIdStr,
28 jfloat requestedRefreshRate) {
29 const ScopedUtfChars name(env, nameObj);
30 const ScopedUtfChars uniqueId(env, uniqueIdStr);
31 sp<IBinder> token(SurfaceComposerClient::createVirtualDisplay(std::string(name.c_str()),
32 bool(secure),
33 std::string(uniqueId.c_str()),
34 requestedRefreshRate));
35 return javaObjectForIBinder(env, token);
36 }
37
nativeDestroyVirtualDisplay(JNIEnv * env,jclass clazz,jobject tokenObj)38 static void nativeDestroyVirtualDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
39 sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
40 if (token == NULL) return;
41 SurfaceComposerClient::destroyVirtualDisplay(token);
42 }
43
nativeOverrideHdrTypes(JNIEnv * env,jclass clazz,jobject tokenObject,jintArray jHdrTypes)44 static void nativeOverrideHdrTypes(JNIEnv* env, jclass clazz, jobject tokenObject,
45 jintArray jHdrTypes) {
46 sp<IBinder> token(ibinderForJavaObject(env, tokenObject));
47 if (token == nullptr || jHdrTypes == nullptr) return;
48
49 ScopedIntArrayRO hdrTypes(env, jHdrTypes);
50 size_t numHdrTypes = hdrTypes.size();
51
52 std::vector<ui::Hdr> hdrTypesVector;
53 hdrTypesVector.reserve(numHdrTypes);
54 for (int i = 0; i < numHdrTypes; i++) {
55 hdrTypesVector.push_back(static_cast<ui::Hdr>(hdrTypes[i]));
56 }
57
58 status_t error = SurfaceComposerClient::overrideHdrTypes(token, hdrTypesVector);
59 if (error != NO_ERROR) {
60 jniThrowExceptionFmt(env, "java/lang/SecurityException",
61 "ACCESS_SURFACE_FLINGER is missing");
62 }
63 }
64
nativeSetHdrConversionMode(JNIEnv * env,jclass clazz,jint hdrConversionMode,jint preferredHdrOutputType,jintArray autoHdrOutputTypes,jint autoHdrOutputTypesLength)65 static int nativeSetHdrConversionMode(JNIEnv* env, jclass clazz, jint hdrConversionMode,
66 jint preferredHdrOutputType, jintArray autoHdrOutputTypes,
67 jint autoHdrOutputTypesLength) {
68 gui::HdrConversionStrategy hdrConversionStrategy;
69 switch (hdrConversionMode) {
70 case gui::IHdrConversionConstants::HdrConversionModePassthrough: {
71 hdrConversionStrategy.set<gui::HdrConversionStrategy::Tag::passthrough>(true);
72 break;
73 }
74 case gui::IHdrConversionConstants::HdrConversionModeAuto: {
75 jint* autoHdrOutputTypesArray = env->GetIntArrayElements(autoHdrOutputTypes, 0);
76 std::vector<int> autoHdrOutputTypesVector(autoHdrOutputTypesLength);
77 for (int i = 0; i < autoHdrOutputTypesLength; i++) {
78 autoHdrOutputTypesVector[i] = autoHdrOutputTypesArray[i];
79 }
80 hdrConversionStrategy.set<gui::HdrConversionStrategy::Tag::autoAllowedHdrTypes>(
81 autoHdrOutputTypesVector);
82 break;
83 }
84 case gui::IHdrConversionConstants::HdrConversionModeForce: {
85 hdrConversionStrategy.set<gui::HdrConversionStrategy::Tag::forceHdrConversion>(
86 preferredHdrOutputType);
87 break;
88 }
89 }
90 ui::Hdr prefHdrType;
91 SurfaceComposerClient::setHdrConversionStrategy(hdrConversionStrategy, &prefHdrType);
92 if (static_cast<jint>(prefHdrType) == 0) {
93 return -1;
94 } else {
95 return static_cast<jint>(prefHdrType);
96 }
97 }
98
nativeGetSupportedHdrOutputTypes(JNIEnv * env,jclass clazz)99 static jintArray nativeGetSupportedHdrOutputTypes(JNIEnv* env, jclass clazz) {
100 std::vector<gui::HdrConversionCapability> hdrConversionCapabilities;
101 SurfaceComposerClient::getHdrConversionCapabilities(&hdrConversionCapabilities);
102
103 // Extract unique HDR output types.
104 std::set<int> hdrOutputTypes;
105 for (const auto& hdrConversionCapability : hdrConversionCapabilities) {
106 // Filter out the value for SDR which is 0.
107 if (hdrConversionCapability.outputType > 0) {
108 hdrOutputTypes.insert(hdrConversionCapability.outputType);
109 }
110 }
111 jintArray array = env->NewIntArray(hdrOutputTypes.size());
112 if (array == nullptr) {
113 jniThrowException(env, "java/lang/OutOfMemoryError", nullptr);
114 return nullptr;
115 }
116 jint* arrayValues = env->GetIntArrayElements(array, 0);
117 size_t index = 0;
118 for (auto hdrOutputType : hdrOutputTypes) {
119 arrayValues[index++] = static_cast<jint>(hdrOutputType);
120 }
121 env->ReleaseIntArrayElements(array, arrayValues, 0);
122 return array;
123 }
124
nativeGetHdrOutputTypesWithLatency(JNIEnv * env,jclass clazz)125 static jintArray nativeGetHdrOutputTypesWithLatency(JNIEnv* env, jclass clazz) {
126 std::vector<gui::HdrConversionCapability> hdrConversionCapabilities;
127 SurfaceComposerClient::getHdrConversionCapabilities(&hdrConversionCapabilities);
128
129 // Extract unique HDR output types with latency.
130 std::set<int> hdrOutputTypes;
131 for (const auto& hdrConversionCapability : hdrConversionCapabilities) {
132 if (hdrConversionCapability.outputType > 0 && hdrConversionCapability.addsLatency) {
133 hdrOutputTypes.insert(hdrConversionCapability.outputType);
134 }
135 }
136 jintArray array = env->NewIntArray(hdrOutputTypes.size());
137 if (array == nullptr) {
138 jniThrowException(env, "java/lang/OutOfMemoryError", nullptr);
139 return nullptr;
140 }
141 jint* arrayValues = env->GetIntArrayElements(array, 0);
142 size_t index = 0;
143 for (auto hdrOutputType : hdrOutputTypes) {
144 arrayValues[index++] = static_cast<jint>(hdrOutputType);
145 }
146 env->ReleaseIntArrayElements(array, arrayValues, 0);
147 return array;
148 }
149
nativeGetHdrOutputConversionSupport(JNIEnv * env,jclass clazz)150 static jboolean nativeGetHdrOutputConversionSupport(JNIEnv* env, jclass clazz) {
151 bool isSupported;
152 status_t err = SurfaceComposerClient::getHdrOutputConversionSupport(&isSupported);
153 if (err == OK) {
154 return isSupported;
155 }
156 return JNI_FALSE;
157 }
158
nativeGetPhysicalDisplayIds(JNIEnv * env,jclass clazz)159 static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
160 const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
161 ScopedLongArrayRW values(env, env->NewLongArray(displayIds.size()));
162 if (values.get() == nullptr) {
163 jniThrowException(env, "java/lang/OutOfMemoryError", nullptr);
164 return nullptr;
165 }
166
167 for (size_t i = 0; i < displayIds.size(); ++i) {
168 values[i] = static_cast<jlong>(displayIds[i].value);
169 }
170
171 return values.getJavaArray();
172 }
173
nativeGetPhysicalDisplayToken(JNIEnv * env,jclass clazz,jlong physicalDisplayId)174 static jobject nativeGetPhysicalDisplayToken(JNIEnv* env, jclass clazz, jlong physicalDisplayId) {
175 const auto id = DisplayId::fromValue<PhysicalDisplayId>(physicalDisplayId);
176 if (!id) return nullptr;
177 sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(*id);
178 return javaObjectForIBinder(env, token);
179 }
180
181 // ----------------------------------------------------------------------------
182
183 static const JNINativeMethod sDisplayMethods[] = {
184 // clang-format off
185 {"nativeCreateVirtualDisplay", "(Ljava/lang/String;ZLjava/lang/String;F)Landroid/os/IBinder;",
186 (void*)nativeCreateVirtualDisplay },
187 {"nativeDestroyVirtualDisplay", "(Landroid/os/IBinder;)V",
188 (void*)nativeDestroyVirtualDisplay },
189 {"nativeOverrideHdrTypes", "(Landroid/os/IBinder;[I)V",
190 (void*)nativeOverrideHdrTypes },
191 {"nativeGetPhysicalDisplayIds", "()[J",
192 (void*)nativeGetPhysicalDisplayIds },
193 {"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;",
194 (void*)nativeGetPhysicalDisplayToken },
195 {"nativeSetHdrConversionMode", "(II[II)I",
196 (void*)nativeSetHdrConversionMode },
197 {"nativeGetSupportedHdrOutputTypes", "()[I",
198 (void*)nativeGetSupportedHdrOutputTypes },
199 {"nativeGetHdrOutputTypesWithLatency", "()[I",
200 (void*)nativeGetHdrOutputTypesWithLatency },
201 {"nativeGetHdrOutputConversionSupport", "()Z",
202 (void*) nativeGetHdrOutputConversionSupport },
203 // clang-format on
204 };
205
register_com_android_server_display_DisplayControl(JNIEnv * env)206 int register_com_android_server_display_DisplayControl(JNIEnv* env) {
207 return jniRegisterNativeMethods(env, "com/android/server/display/DisplayControl",
208 sDisplayMethods, NELEM(sDisplayMethods));
209 }
210
211 } // namespace android
212