Merge "Export AIDL files as a filegroup for framework.jar"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index aba08d9..4b67d8f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1085,7 +1085,7 @@
CommandOptions::WithTimeout(90).DropRoot().Build());
} else {
RunDumpsys("DUMPSYS", {"--skip", "meminfo", "cpuinfo"},
- CommandOptions::WithTimeout(90).Build(), 10);
+ CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
}
}
@@ -1307,8 +1307,10 @@
printf("== Android Framework Services\n");
printf("========================================================\n");
- RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(), 10);
- RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(), 10);
+ RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
+ SEC_TO_MSEC(10));
+ RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
+ SEC_TO_MSEC(10));
printf("========================================================\n");
printf("== Running Application Services\n");
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index e10fb6c..48d5b36 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -342,6 +342,56 @@
#endif
}
+static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
+ if (!property_get_bool("dalvik.vm.usejitprofiles", false)) {
+ return true;
+ }
+
+ int32_t uid = multiuser_get_uid(userId, appId);
+ int shared_app_gid = multiuser_get_shared_gid(userId, appId);
+ if (shared_app_gid == -1) {
+ // TODO(calin): this should no longer be possible but do not continue if we don't get
+ // a valid shared gid.
+ PLOG(WARNING) << "Invalid shared_app_gid for " << packageName;
+ return true;
+ }
+
+ const std::string profile_dir =
+ create_primary_current_profile_package_dir_path(userId, packageName);
+ // read-write-execute only for the app user.
+ if (fs_prepare_dir_strict(profile_dir.c_str(), 0700, uid, uid) != 0) {
+ PLOG(ERROR) << "Failed to prepare " << profile_dir;
+ return false;
+ }
+ const std::string profile_file = create_current_profile_path(userId, packageName,
+ /*is_secondary_dex*/false);
+ // read-write only for the app user.
+ if (fs_prepare_file_strict(profile_file.c_str(), 0600, uid, uid) != 0) {
+ PLOG(ERROR) << "Failed to prepare " << profile_file;
+ return false;
+ }
+
+ const std::string ref_profile_path =
+ create_primary_reference_profile_package_dir_path(packageName);
+
+ // Prepare the reference profile directory. Note that we use the non strict version of
+ // fs_prepare_dir. This will fix the permission and the ownership to the correct values.
+ // This is particularly important given that in O there were some fixes for how the
+ // shared_app_gid is computed.
+ //
+ // Note that by the time we get here we know that we are using a correct uid (otherwise
+ // prepare_app_dir and the above fs_prepare_file_strict which check the uid). So we
+ // are sure that the gid being used belongs to the owning app and not someone else.
+ //
+ // dex2oat/profman runs under the shared app gid and it needs to read/write reference profiles.
+ if (fs_prepare_dir(ref_profile_path.c_str(), 0770, AID_SYSTEM, shared_app_gid) != 0) {
+ PLOG(ERROR) << "Failed to prepare " << ref_profile_path;
+ return false;
+ }
+
+ return true;
+}
+
binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid,
const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) {
@@ -417,28 +467,8 @@
return error("Failed to set hard quota " + path);
}
- if (property_get_bool("dalvik.vm.usejitprofiles", false)) {
- const std::string profile_dir =
- create_primary_current_profile_package_dir_path(userId, pkgname);
- // read-write-execute only for the app user.
- if (fs_prepare_dir_strict(profile_dir.c_str(), 0700, uid, uid) != 0) {
- return error("Failed to prepare " + profile_dir);
- }
- const std::string profile_file = create_current_profile_path(userId, pkgname,
- /*is_secondary_dex*/false);
- // read-write only for the app user.
- if (fs_prepare_file_strict(profile_file.c_str(), 0600, uid, uid) != 0) {
- return error("Failed to prepare " + profile_file);
- }
- const std::string ref_profile_path =
- create_primary_reference_profile_package_dir_path(pkgname);
- // dex2oat/profman runs under the shared app gid and it needs to read/write reference
- // profiles.
- int shared_app_gid = multiuser_get_shared_gid(0, appId);
- if ((shared_app_gid != -1) && fs_prepare_dir_strict(
- ref_profile_path.c_str(), 0700, shared_app_gid, shared_app_gid) != 0) {
- return error("Failed to prepare " + ref_profile_path);
- }
+ if (!prepare_app_profile_dir(packageName, appId, userId)) {
+ return error("Failed to prepare profiles for " + packageName);
}
}
return ok();
@@ -1833,6 +1863,29 @@
return ok();
}
+binder::Status InstalldNativeService::snapshotProfile(int32_t appId, const std::string& packageName,
+ const std::string& codePath, bool* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ *_aidl_return = snapshot_profile(appId, packageName, codePath);
+ return ok();
+}
+
+binder::Status InstalldNativeService::destroyProfileSnapshot(const std::string& packageName,
+ const std::string& codePath) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ std::string snapshot = create_snapshot_profile_path(packageName, codePath);
+ if ((unlink(snapshot.c_str()) != 0) && (errno != ENOENT)) {
+ return error("Failed to destroy profile snapshot for " + packageName + ":" + codePath);
+ }
+ return ok();
+}
+
binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t uid,
const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 5167a14..eb7231c 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -96,6 +96,11 @@
binder::Status clearAppProfiles(const std::string& packageName);
binder::Status destroyAppProfiles(const std::string& packageName);
+ binder::Status snapshotProfile(int32_t appId, const std::string& packageName,
+ const std::string& codePath, bool* _aidl_return);
+ binder::Status destroyProfileSnapshot(const std::string& packageName,
+ const std::string& codePath);
+
binder::Status idmap(const std::string& targetApkPath, const std::string& overlayApkPath,
int32_t uid);
binder::Status removeIdmap(const std::string& overlayApkPath);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 0f9862d..16ba2af 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -62,6 +62,9 @@
void clearAppProfiles(@utf8InCpp String packageName);
void destroyAppProfiles(@utf8InCpp String packageName);
+ boolean snapshotProfile(int appId, @utf8InCpp String packageName, @utf8InCpp String codePath);
+ void destroyProfileSnapshot(@utf8InCpp String packageName, @utf8InCpp String codePath);
+
void idmap(@utf8InCpp String targetApkPath, @utf8InCpp String overlayApkPath, int uid);
void removeIdmap(@utf8InCpp String overlayApkPath);
void rmPackageDir(@utf8InCpp String packageDir);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 6f160b9..beffe00 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -566,14 +566,12 @@
}
}
-static bool create_profile(int uid, const std::string& profile) {
- unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), O_CREAT | O_NOFOLLOW, 0600)));
+static unique_fd create_profile(uid_t uid, const std::string& profile, int32_t flags) {
+ unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), flags, 0600)));
if (fd.get() < 0) {
- if (errno == EEXIST) {
- return true;
- } else {
+ if (errno != EEXIST) {
PLOG(ERROR) << "Failed to create profile " << profile;
- return false;
+ return invalid_unique_fd();
}
}
// Profiles should belong to the app; make sure of that by giving ownership to
@@ -581,27 +579,26 @@
// since dex2oat/profman will fail with SElinux denials.
if (fchown(fd.get(), uid, uid) < 0) {
PLOG(ERROR) << "Could not chwon profile " << profile;
- return false;
+ return invalid_unique_fd();
}
- return true;
+ return fd;
}
-static unique_fd open_profile(int uid, const std::string& profile, bool read_write) {
- // Check if we need to open the profile for a read-write operation. If so, we
- // might need to create the profile since the file might not be there. Reference
- // profiles are created on the fly so they might not exist beforehand.
- if (read_write) {
- if (!create_profile(uid, profile)) {
- return invalid_unique_fd();
- }
- }
- int flags = read_write ? O_RDWR : O_RDONLY;
+static unique_fd open_profile(uid_t uid, const std::string& profile, int32_t flags) {
// Do not follow symlinks when opening a profile:
// - primary profiles should not contain symlinks in their paths
// - secondary dex paths should have been already resolved and validated
flags |= O_NOFOLLOW;
- unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), flags)));
+ // Check if we need to create the profile
+ // Reference profiles and snapshots are created on the fly; so they might not exist beforehand.
+ unique_fd fd;
+ if ((flags & O_CREAT) != 0) {
+ fd = create_profile(uid, profile, flags);
+ } else {
+ fd.reset(TEMP_FAILURE_RETRY(open(profile.c_str(), flags)));
+ }
+
if (fd.get() < 0) {
if (errno != ENOENT) {
// Profiles might be missing for various reasons. For example, in a
@@ -621,13 +618,19 @@
static unique_fd open_current_profile(uid_t uid, userid_t user, const std::string& location,
bool is_secondary_dex) {
std::string profile = create_current_profile_path(user, location, is_secondary_dex);
- return open_profile(uid, profile, /*read_write*/false);
+ return open_profile(uid, profile, O_RDONLY);
}
static unique_fd open_reference_profile(uid_t uid, const std::string& location, bool read_write,
bool is_secondary_dex) {
std::string profile = create_reference_profile_path(location, is_secondary_dex);
- return open_profile(uid, profile, read_write);
+ return open_profile(uid, profile, read_write ? (O_CREAT | O_RDWR) : O_RDONLY);
+}
+
+static unique_fd open_spnashot_profile(uid_t uid, const std::string& package_name,
+ const std::string& code_path) {
+ std::string profile = create_snapshot_profile_path(package_name, code_path);
+ return open_profile(uid, profile, O_CREAT | O_RDWR | O_TRUNC);
}
static void open_profile_files(uid_t uid, const std::string& location, bool is_secondary_dex,
@@ -2396,5 +2399,42 @@
}
}
+bool snapshot_profile(int32_t app_id, const std::string& package_name,
+ const std::string& code_path) {
+ int app_shared_gid = multiuser_get_shared_gid(/*user_id*/ 0, app_id);
+
+ unique_fd snapshot_fd = open_spnashot_profile(AID_SYSTEM, package_name, code_path);
+ if (snapshot_fd < 0) {
+ return false;
+ }
+
+ std::vector<unique_fd> profiles_fd;
+ unique_fd reference_profile_fd;
+ open_profile_files(app_shared_gid, package_name, /*is_secondary_dex*/ false, &profiles_fd,
+ &reference_profile_fd);
+ if (profiles_fd.empty() || (reference_profile_fd.get() < 0)) {
+ return false;
+ }
+
+ profiles_fd.push_back(std::move(reference_profile_fd));
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ /* child -- drop privileges before continuing */
+ drop_capabilities(app_shared_gid);
+ run_profman_merge(profiles_fd, snapshot_fd);
+ exit(42); /* only get here on exec failure */
+ }
+
+ /* parent */
+ int return_code = wait_child(pid);
+ if (!WIFEXITED(return_code)) {
+ LOG(WARNING) << "profman failed for " << package_name << ":" << code_path;
+ return false;
+ }
+
+ return true;
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 798e211..8a9ffd2 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -50,6 +50,17 @@
// the reference profiles accessible with open_reference_profile().
bool analyze_primary_profiles(uid_t uid, const std::string& pkgname);
+// Create a snapshot of the profile information for the given package and code path.
+// The profile snapshot is the aggregation of all existing profiles (all current user
+// profiles & the reference profile) and is meant to capture the all the profile information
+// without performing a merge into the reference profile which might impact future dex2oat
+// compilations.
+// The snapshot is created next to the reference profile of the package and the
+// ownership is assigned to AID_SYSTEM.
+// The snapshot location is reference_profile_location.snapshot. If a snapshot is already
+// there, it will be truncated and overwritten.
+bool snapshot_profile(int32_t app_id, const std::string& package, const std::string& code_path);
+
bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths);
bool copy_system_profile(const std::string& system_profile,
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 821b96f..05d7b6c 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -14,20 +14,33 @@
* limitations under the License.
*/
+#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+
#include <cutils/properties.h>
+
#include <gtest/gtest.h>
+#include <selinux/android.h>
+#include <selinux/avc.h>
+
#include "dexopt.h"
#include "InstalldNativeService.h"
#include "globals.h"
#include "tests/test_utils.h"
#include "utils.h"
+using android::base::ReadFully;
+using android::base::unique_fd;
+
namespace android {
namespace installd {
@@ -76,6 +89,42 @@
::chmod(path.c_str(), mode);
}
+static int log_callback(int type, const char *fmt, ...) { // NOLINT
+ va_list ap;
+ int priority;
+
+ switch (type) {
+ case SELINUX_WARNING:
+ priority = ANDROID_LOG_WARN;
+ break;
+ case SELINUX_INFO:
+ priority = ANDROID_LOG_INFO;
+ break;
+ default:
+ priority = ANDROID_LOG_ERROR;
+ break;
+ }
+ va_start(ap, fmt);
+ LOG_PRI_VA(priority, "SELinux", fmt, ap);
+ va_end(ap);
+ return 0;
+}
+
+static bool init_selinux() {
+ int selinux_enabled = (is_selinux_enabled() > 0);
+
+ union selinux_callback cb;
+ cb.func_log = log_callback;
+ selinux_set_callback(SELINUX_CB_LOG, cb);
+
+ if (selinux_enabled && selinux_status_open(true) < 0) {
+ LOG(ERROR) << "Could not open selinux status; exiting";
+ return false;
+ }
+
+ return true;
+}
+
// Base64 encoding of a simple dex files with 2 methods.
static const char kDexFile[] =
"UEsDBBQAAAAIAOiOYUs9y6BLCgEAABQCAAALABwAY2xhc3Nlcy5kZXhVVAkAA/Ns+lkOHv1ZdXgL"
@@ -95,9 +144,11 @@
static constexpr uid_t kSystemGid = 1000;
static constexpr int32_t kOSdkVersion = 25;
static constexpr int32_t kAppDataFlags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
- static constexpr uid_t kTestAppUid = 19999;
- static constexpr gid_t kTestAppGid = 19999;
static constexpr int32_t kTestUserId = 0;
+ static constexpr uid_t kTestAppId = 19999;
+
+ const gid_t kTestAppUid = multiuser_get_uid(kTestUserId, kTestAppId);
+ const uid_t kTestAppGid = multiuser_get_shared_gid(kTestUserId, kTestAppId);
InstalldNativeService* service_;
std::unique_ptr<std::string> volume_uuid_;
@@ -116,15 +167,18 @@
virtual void SetUp() {
setenv("ANDROID_LOG_TAGS", "*:v", 1);
android::base::InitLogging(nullptr);
-
+ // Initialize the globals holding the file system main paths (/data/, /system/ etc..).
+ // This is needed in order to compute the application and profile paths.
+ ASSERT_TRUE(init_globals_from_data_and_root());
+ // Initialize selinux log callbacks.
+ // This ensures that selinux is up and running and re-directs the selinux messages
+ // to logcat (in order to make it easier to investigate test results).
+ ASSERT_TRUE(init_selinux());
service_ = new InstalldNativeService();
volume_uuid_ = nullptr;
package_name_ = "com.installd.test.dexopt";
se_info_ = "default";
-
- init_globals_from_data_and_root();
-
app_apk_dir_ = android_app_dir + package_name_;
create_mock_app();
@@ -183,16 +237,19 @@
}
- std::string get_secondary_dex_artifact(const std::string& path, const std::string& type) {
+ std::string GetSecondaryDexArtifact(const std::string& path, const std::string& type) {
std::string::size_type end = path.rfind('.');
std::string::size_type start = path.rfind('/', end);
return path.substr(0, start) + "/oat/" + kRuntimeIsa + "/" +
path.substr(start + 1, end - start) + type;
}
- void compile_secondary_dex(const std::string& path, int32_t dex_storage_flag,
+ void CompileSecondaryDex(const std::string& path, int32_t dex_storage_flag,
bool should_binder_call_succeed, bool should_dex_be_compiled = true,
- int uid = kTestAppUid) {
+ int32_t uid = -1) {
+ if (uid == -1) {
+ uid = kTestAppUid;
+ }
std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_));
int32_t dexopt_needed = 0; // does not matter;
std::unique_ptr<std::string> out_path = nullptr; // does not matter
@@ -216,9 +273,9 @@
downgrade);
ASSERT_EQ(should_binder_call_succeed, result.isOk());
int expected_access = should_dex_be_compiled ? 0 : -1;
- std::string odex = get_secondary_dex_artifact(path, "odex");
- std::string vdex = get_secondary_dex_artifact(path, "vdex");
- std::string art = get_secondary_dex_artifact(path, "art");
+ std::string odex = GetSecondaryDexArtifact(path, "odex");
+ std::string vdex = GetSecondaryDexArtifact(path, "vdex");
+ std::string art = GetSecondaryDexArtifact(path, "art");
ASSERT_EQ(expected_access, access(odex.c_str(), R_OK));
ASSERT_EQ(expected_access, access(vdex.c_str(), R_OK));
ASSERT_EQ(-1, access(art.c_str(), R_OK)); // empty profiles do not generate an image.
@@ -226,7 +283,10 @@
void reconcile_secondary_dex(const std::string& path, int32_t storage_flag,
bool should_binder_call_succeed, bool should_dex_exist, bool should_dex_be_deleted,
- int uid = kTestAppUid, std::string* package_override = nullptr) {
+ int32_t uid = -1, std::string* package_override = nullptr) {
+ if (uid == -1) {
+ uid = kTestAppUid;
+ }
std::vector<std::string> isas;
isas.push_back(kRuntimeIsa);
bool out_secondary_dex_exists = false;
@@ -243,56 +303,64 @@
ASSERT_EQ(should_dex_exist, out_secondary_dex_exists);
int expected_access = should_dex_be_deleted ? -1 : 0;
- std::string odex = get_secondary_dex_artifact(path, "odex");
- std::string vdex = get_secondary_dex_artifact(path, "vdex");
- std::string art = get_secondary_dex_artifact(path, "art");
+ std::string odex = GetSecondaryDexArtifact(path, "odex");
+ std::string vdex = GetSecondaryDexArtifact(path, "vdex");
+ std::string art = GetSecondaryDexArtifact(path, "art");
ASSERT_EQ(expected_access, access(odex.c_str(), F_OK));
ASSERT_EQ(expected_access, access(vdex.c_str(), F_OK));
ASSERT_EQ(-1, access(art.c_str(), R_OK)); // empty profiles do not generate an image.
}
+
+ void CheckFileAccess(const std::string& file, uid_t uid, gid_t gid, mode_t mode) {
+ struct stat st;
+ ASSERT_EQ(0, stat(file.c_str(), &st));
+ ASSERT_EQ(uid, st.st_uid);
+ ASSERT_EQ(gid, st.st_gid);
+ ASSERT_EQ(mode, st.st_mode);
+ }
};
TEST_F(DexoptTest, DexoptSecondaryCe) {
LOG(INFO) << "DexoptSecondaryCe";
- compile_secondary_dex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
+ CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
/*binder_ok*/ true, /*compile_ok*/ true);
}
TEST_F(DexoptTest, DexoptSecondaryCeLink) {
LOG(INFO) << "DexoptSecondaryCeLink";
- compile_secondary_dex(secondary_dex_ce_link_, DEXOPT_STORAGE_CE,
+ CompileSecondaryDex(secondary_dex_ce_link_, DEXOPT_STORAGE_CE,
/*binder_ok*/ true, /*compile_ok*/ true);
}
TEST_F(DexoptTest, DexoptSecondaryDe) {
LOG(INFO) << "DexoptSecondaryDe";
- compile_secondary_dex(secondary_dex_de_, DEXOPT_STORAGE_DE,
+ CompileSecondaryDex(secondary_dex_de_, DEXOPT_STORAGE_DE,
/*binder_ok*/ true, /*compile_ok*/ true);
}
TEST_F(DexoptTest, DexoptSecondaryDoesNotExist) {
LOG(INFO) << "DexoptSecondaryDoesNotExist";
// If the file validates but does not exist we do not treat it as an error.
- compile_secondary_dex(secondary_dex_ce_ + "not.there", DEXOPT_STORAGE_CE,
+ CompileSecondaryDex(secondary_dex_ce_ + "not.there", DEXOPT_STORAGE_CE,
/*binder_ok*/ true, /*compile_ok*/ false);
}
TEST_F(DexoptTest, DexoptSecondaryStorageValidationError) {
LOG(INFO) << "DexoptSecondaryStorageValidationError";
- compile_secondary_dex(secondary_dex_ce_, DEXOPT_STORAGE_DE,
+ CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_DE,
/*binder_ok*/ false, /*compile_ok*/ false);
}
TEST_F(DexoptTest, DexoptSecondaryAppOwnershipValidationError) {
LOG(INFO) << "DexoptSecondaryAppOwnershipValidationError";
- compile_secondary_dex("/data/data/random.app/secondary.jar", DEXOPT_STORAGE_CE,
+ CompileSecondaryDex("/data/data/random.app/secondary.jar", DEXOPT_STORAGE_CE,
/*binder_ok*/ false, /*compile_ok*/ false);
}
TEST_F(DexoptTest, DexoptSecondaryAcessViaDifferentUidError) {
LOG(INFO) << "DexoptSecondaryAcessViaDifferentUidError";
- compile_secondary_dex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
+ CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
/*binder_ok*/ false, /*compile_ok*/ false, kSystemUid);
}
@@ -300,9 +368,9 @@
class ReconcileTest : public DexoptTest {
virtual void SetUp() {
DexoptTest::SetUp();
- compile_secondary_dex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
+ CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
/*binder_ok*/ true, /*compile_ok*/ true);
- compile_secondary_dex(secondary_dex_de_, DEXOPT_STORAGE_DE,
+ CompileSecondaryDex(secondary_dex_de_, DEXOPT_STORAGE_DE,
/*binder_ok*/ true, /*compile_ok*/ true);
}
};
@@ -355,5 +423,191 @@
/*binder_ok*/ true, /*dex_ok */ false, /*odex_deleted*/ false, kSystemUid);
}
+class ProfileTest : public DexoptTest {
+ protected:
+ std::string cur_profile_;
+ std::string ref_profile_;
+ std::string snap_profile_;
+
+ virtual void SetUp() {
+ DexoptTest::SetUp();
+ cur_profile_ = create_current_profile_path(
+ kTestUserId, package_name_, /*is_secondary_dex*/ false);
+ ref_profile_ = create_reference_profile_path(package_name_, /*is_secondary_dex*/ false);
+ snap_profile_ = create_snapshot_profile_path(package_name_, "base.jar");
+ }
+
+ void SetupProfile(const std::string& path, uid_t uid, gid_t gid, mode_t mode, int32_t seed) {
+ run_cmd("profman --generate-test-profile-seed=" + std::to_string(seed) +
+ " --generate-test-profile-num-dex=2 --generate-test-profile=" + path);
+ ::chmod(path.c_str(), mode);
+ ::chown(path.c_str(), uid, gid);
+ }
+
+ void SetupProfiles(bool setup_ref) {
+ SetupProfile(cur_profile_, kTestAppUid, kTestAppGid, 0600, 1);
+ if (setup_ref) {
+ SetupProfile(ref_profile_, kTestAppUid, kTestAppGid, 0060, 2);
+ }
+ }
+
+ void SnapshotProfile(int32_t appid, const std::string& package_name, bool expected_result) {
+ bool result;
+ binder::Status binder_result = service_->snapshotProfile(
+ appid, package_name, "base.jar", &result);
+ ASSERT_TRUE(binder_result.isOk());
+ ASSERT_EQ(expected_result, result);
+
+ if (!expected_result) {
+ // Do not check the files if we expect to fail.
+ return;
+ }
+
+ // Check that the snapshot was created witht he expected acess flags.
+ CheckFileAccess(snap_profile_, kSystemUid, kSystemGid, 0600 | S_IFREG);
+
+ // The snapshot should be equivalent to the merge of profiles.
+ std::string expected_profile_content = snap_profile_ + ".expected";
+ run_cmd("rm -f " + expected_profile_content);
+ run_cmd("touch " + expected_profile_content);
+ run_cmd("profman --profile-file=" + cur_profile_ +
+ " --profile-file=" + ref_profile_ +
+ " --reference-profile-file=" + expected_profile_content);
+
+ ASSERT_TRUE(AreFilesEqual(expected_profile_content, snap_profile_));
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ /* child */
+ TransitionToSystemServer();
+
+ // System server should be able to open the the spanshot.
+ unique_fd fd(open(snap_profile_.c_str(), O_RDONLY));
+ ASSERT_TRUE(fd > -1) << "Failed to open profile as kSystemUid: " << strerror(errno);
+ _exit(0);
+ }
+ /* parent */
+ ASSERT_TRUE(WIFEXITED(wait_child(pid)));
+ }
+
+ private:
+ void TransitionToSystemServer() {
+ ASSERT_TRUE(DropCapabilities(kSystemUid, kSystemGid));
+ int32_t res = selinux_android_setcontext(
+ kSystemUid, true, se_info_.c_str(), "system_server");
+ ASSERT_EQ(0, res) << "Failed to setcon " << strerror(errno);
+ }
+
+ bool AreFilesEqual(const std::string& file1, const std::string& file2) {
+ std::vector<uint8_t> content1;
+ std::vector<uint8_t> content2;
+
+ if (!ReadAll(file1, &content1)) return false;
+ if (!ReadAll(file2, &content2)) return false;
+ return content1 == content2;
+ }
+
+ bool ReadAll(const std::string& file, std::vector<uint8_t>* content) {
+ unique_fd fd(open(file.c_str(), O_RDONLY));
+ if (fd < 0) {
+ PLOG(ERROR) << "Failed to open " << file;
+ return false;
+ }
+ struct stat st;
+ if (fstat(fd, &st) != 0) {
+ PLOG(ERROR) << "Failed to stat " << file;
+ return false;
+ }
+ content->resize(st.st_size);
+ bool result = ReadFully(fd, content->data(), content->size());
+ if (!result) {
+ PLOG(ERROR) << "Failed to read " << file;
+ }
+ return result;
+ }
+};
+
+TEST_F(ProfileTest, ProfileSnapshotOk) {
+ LOG(INFO) << "ProfileSnapshotOk";
+
+ SetupProfiles(/*setup_ref*/ true);
+ SnapshotProfile(kTestAppId, package_name_, /*expected_result*/ true);
+}
+
+// The reference profile is created on the fly. We need to be able to
+// snapshot without one.
+TEST_F(ProfileTest, ProfileSnapshotOkNoReference) {
+ LOG(INFO) << "ProfileSnapshotOkNoReference";
+
+ SetupProfiles(/*setup_ref*/ false);
+ SnapshotProfile(kTestAppId, package_name_, /*expected_result*/ true);
+}
+
+TEST_F(ProfileTest, ProfileSnapshotFailWrongPackage) {
+ LOG(INFO) << "ProfileSnapshotFailWrongPackage";
+
+ SetupProfiles(/*setup_ref*/ true);
+ SnapshotProfile(kTestAppId, "not.there", /*expected_result*/ false);
+}
+
+TEST_F(ProfileTest, ProfileSnapshotDestroySnapshot) {
+ LOG(INFO) << "ProfileSnapshotDestroySnapshot";
+
+ SetupProfiles(/*setup_ref*/ true);
+ SnapshotProfile(kTestAppId, package_name_, /*expected_result*/ true);
+
+ binder::Status binder_result = service_->destroyProfileSnapshot(package_name_, "base.jar");
+ ASSERT_TRUE(binder_result.isOk());
+ struct stat st;
+ ASSERT_EQ(-1, stat(snap_profile_.c_str(), &st));
+ ASSERT_EQ(ENOENT, errno);
+}
+
+TEST_F(ProfileTest, ProfileDirOk) {
+ LOG(INFO) << "ProfileDirOk";
+
+ std::string cur_profile_dir = create_primary_current_profile_package_dir_path(
+ kTestUserId, package_name_);
+ std::string cur_profile_file = create_current_profile_path(kTestUserId, package_name_,
+ /*is_secondary_dex*/false);
+ std::string ref_profile_dir = create_primary_reference_profile_package_dir_path(package_name_);
+
+ CheckFileAccess(cur_profile_dir, kTestAppUid, kTestAppUid, 0700 | S_IFDIR);
+ CheckFileAccess(cur_profile_file, kTestAppUid, kTestAppUid, 0600 | S_IFREG);
+ CheckFileAccess(ref_profile_dir, kSystemUid, kTestAppGid, 0770 | S_IFDIR);
+}
+
+// Verify that the profile directories are fixed up during an upgrade.
+// (The reference profile directory is prepared lazily).
+TEST_F(ProfileTest, ProfileDirOkAfterFixup) {
+ LOG(INFO) << "ProfileDirOkAfterFixup";
+
+ std::string cur_profile_dir = create_primary_current_profile_package_dir_path(
+ kTestUserId, package_name_);
+ std::string cur_profile_file = create_current_profile_path(kTestUserId, package_name_,
+ /*is_secondary_dex*/false);
+ std::string ref_profile_dir = create_primary_reference_profile_package_dir_path(package_name_);
+
+ // Simulate a pre-P setup by changing the owner to kTestAppGid and permissions to 0700.
+ ASSERT_EQ(0, chown(ref_profile_dir.c_str(), kTestAppGid, kTestAppGid));
+ ASSERT_EQ(0, chmod(ref_profile_dir.c_str(), 0700));
+
+ // Run createAppData again which will offer to fix-up the profile directories.
+ ASSERT_TRUE(service_->createAppData(
+ volume_uuid_,
+ package_name_,
+ kTestUserId,
+ kAppDataFlags,
+ kTestAppUid,
+ se_info_,
+ kOSdkVersion,
+ &ce_data_inode_).isOk());
+
+ // Check the file access.
+ CheckFileAccess(cur_profile_dir, kTestAppUid, kTestAppUid, 0700 | S_IFDIR);
+ CheckFileAccess(cur_profile_file, kTestAppUid, kTestAppUid, 0600 | S_IFREG);
+ CheckFileAccess(ref_profile_dir, kSystemUid, kTestAppGid, 0770 | S_IFDIR);
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index a6a4451..49da85d 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -350,6 +350,12 @@
create_reference_profile_path("com.example", /*is_secondary*/false));
}
+TEST_F(UtilsTest, CreateProfileSnapshot) {
+ std::string expected =
+ create_primary_reference_profile_package_dir_path("com.example") + "/primary.prof.snapshot";
+ EXPECT_EQ(expected, create_snapshot_profile_path("com.example", "base.apk"));
+}
+
TEST_F(UtilsTest, CreateSecondaryCurrentProfile) {
EXPECT_EQ("/data/user/0/com.example/oat/secondary.dex.cur.prof",
create_current_profile_path(/*user*/0,
diff --git a/cmds/installd/tests/test_utils.h b/cmds/installd/tests/test_utils.h
index 7d1162e..b8785c6 100644
--- a/cmds/installd/tests/test_utils.h
+++ b/cmds/installd/tests/test_utils.h
@@ -1,6 +1,9 @@
-#include <android-base/logging.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/capability.h>
+
+#include <android-base/logging.h>
+#include <selinux/android.h>
uint8_t kBase64Map[256] = {
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
@@ -105,3 +108,27 @@
}
return true;
}
+
+// TODO(calin): fix dexopt drop_capabilities and move to general utils (b/69678790).
+bool DropCapabilities(uid_t uid, gid_t gid) {
+ if (setgid(gid) != 0) {
+ PLOG(ERROR) << "setgid failed: " << gid;
+ return false;
+ }
+ if (setuid(uid) != 0) {
+ PLOG(ERROR) << "setuid failed: " << uid;
+ return false;
+ }
+ // drop capabilities
+ struct __user_cap_header_struct capheader;
+ struct __user_cap_data_struct capdata[2];
+ memset(&capheader, 0, sizeof(capheader));
+ memset(&capdata, 0, sizeof(capdata));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ if (capset(&capheader, &capdata[0]) < 0) {
+ PLOG(ERROR) << "capset failed";
+ return false;
+ }
+
+ return true;
+}
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 7dca7c6..61c9c8f 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -236,6 +236,7 @@
const std::string PROFILE_EXT = ".prof";
const std::string CURRENT_PROFILE_EXT = ".cur";
const std::string PRIMARY_PROFILE_NAME = "primary" + PROFILE_EXT;
+const std::string SNAPSHOT_PROFILE_EXT = ".snapshot";
// Gets the parent directory and the file name for the given secondary dex path.
// Returns true on success, false on failure (if the dex_path does not have the expected
@@ -289,6 +290,14 @@
}
}
+std::string create_snapshot_profile_path(const std::string& package,
+ const std::string& code_path ATTRIBUTE_UNUSED) {
+ // TODD(calin): code_path is ignored for now. It will be used when each split gets its own
+ // profile file.
+ std::string ref_profile = create_reference_profile_path(package, /*is_secondary_dex*/ false);
+ return ref_profile + SNAPSHOT_PROFILE_EXT;
+}
+
std::vector<userid_t> get_known_users(const char* volume_uuid) {
std::vector<userid_t> users;
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index b90caf9..5391061 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -83,6 +83,7 @@
userid_t user, const std::string& package_name, bool is_secondary_dex);
std::string create_reference_profile_path(
const std::string& package_name, bool is_secondary_dex);
+std::string create_snapshot_profile_path(const std::string& package, const std::string& code_path);
std::vector<userid_t> get_known_users(const char* volume_uuid);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 973302c..c21c5e3 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -124,12 +124,13 @@
virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
const sp<IGraphicBufferProducer>& producer,
- ISurfaceComposer::Rotation rotation) {
+ const Rect& sourceCrop, float frameScale) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeStrongBinder(layerHandleBinder);
data.writeStrongBinder(IInterface::asBinder(producer));
- data.writeInt32(static_cast<int32_t>(rotation));
+ data.write(sourceCrop);
+ data.writeFloat(frameScale);
remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
return reply.readInt32();
}
@@ -605,10 +606,11 @@
sp<IBinder> layerHandleBinder = data.readStrongBinder();
sp<IGraphicBufferProducer> producer =
interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
- int32_t rotation = data.readInt32();
+ Rect sourceCrop(Rect::EMPTY_RECT);
+ data.read(sourceCrop);
+ float frameScale = data.readFloat();
- status_t res = captureLayers(layerHandleBinder, producer,
- static_cast<ISurfaceComposer::Rotation>(rotation));
+ status_t res = captureLayers(layerHandleBinder, producer, sourceCrop, frameScale);
reply->writeInt32(res);
return NO_ERROR;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 2adc273..2466d25 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -757,11 +757,34 @@
status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle,
const sp<IGraphicBufferProducer>& producer,
- uint32_t rotation) {
+ Rect sourceCrop, float frameScale) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == NULL) return NO_INIT;
- return s->captureLayers(layerHandle, producer,
- static_cast<ISurfaceComposer::Rotation>(rotation));
+ return s->captureLayers(layerHandle, producer, sourceCrop, frameScale);
+}
+
+status_t ScreenshotClient::captureLayersToBuffer(const sp<IBinder>& layerHandle, Rect sourceCrop,
+ float frameScale, sp<GraphicBuffer>* outBuffer) {
+ sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ if (s == NULL) return NO_INIT;
+
+ sp<IGraphicBufferConsumer> gbpConsumer;
+ sp<IGraphicBufferProducer> producer;
+ BufferQueue::createBufferQueue(&producer, &gbpConsumer);
+ sp<BufferItemConsumer> consumer(new BufferItemConsumer(gbpConsumer,
+ GRALLOC_USAGE_HW_TEXTURE |
+ GRALLOC_USAGE_SW_READ_NEVER |
+ GRALLOC_USAGE_SW_WRITE_NEVER,
+ 1, true));
+
+ status_t ret = s->captureLayers(layerHandle, producer, sourceCrop, frameScale);
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+ BufferItem b;
+ consumer->acquireBuffer(&b, 0, true);
+ *outBuffer = b.mGraphicBuffer;
+ return ret;
}
ScreenshotClient::ScreenshotClient()
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index e9fc8fd..4a86021 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -187,7 +187,7 @@
// ConsumerBase::releaseBufferLocked.
virtual status_t releaseBufferLocked(int slot,
const sp<GraphicBuffer> graphicBuffer,
- EGLDisplay display, EGLSyncKHR eglFence);
+ EGLDisplay display = EGL_NO_DISPLAY, EGLSyncKHR eglFence = EGL_NO_SYNC_KHR);
// returns true iff the slot still has the graphicBuffer in it.
bool stillTracking(int slot, const sp<GraphicBuffer> graphicBuffer);
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 13e7473..1e4c329 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -176,7 +176,7 @@
virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
const sp<IGraphicBufferProducer>& producer,
- Rotation rotation = eRotateNone) = 0;
+ const Rect& sourceCrop, float frameScale = 1.0) = 0;
/* Clears the frame statistics for animations.
*
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 87fdfae..b0fa922 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -297,8 +297,12 @@
bool useIdentityTransform,
uint32_t rotation,
sp<GraphicBuffer>* outbuffer);
+
static status_t captureLayers(const sp<IBinder>& layerHandle,
- const sp<IGraphicBufferProducer>& producer, uint32_t rotation);
+ const sp<IGraphicBufferProducer>& producer, Rect sourceCrop,
+ float frameScale);
+ static status_t captureLayersToBuffer(const sp<IBinder>& layerHandle, Rect sourceCrop,
+ float frameScale, sp<GraphicBuffer>* outBuffer);
private:
mutable sp<CpuConsumer> mCpuConsumer;
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 660680b..ac4eb0c 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -531,7 +531,7 @@
Rotation /*rotation*/) override { return NO_ERROR; }
virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/,
const sp<IGraphicBufferProducer>& /*producer*/,
- ISurfaceComposer::Rotation /*rotation*/) override {
+ const Rect& /*sourceCrop*/, float /*frameScale*/) override {
return NO_ERROR;
}
status_t clearAnimationFrameStats() override { return NO_ERROR; }
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index ecee8ce..deead06 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -41,6 +41,7 @@
RenderEngine/ProgramCache.cpp \
RenderEngine/GLExtensions.cpp \
RenderEngine/RenderEngine.cpp \
+ RenderEngine/Surface.cpp \
RenderEngine/Texture.cpp \
RenderEngine/GLES20RenderEngine.cpp \
LayerProtoHelper.cpp \
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 2fa17e9..0d947b1 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -109,13 +109,14 @@
}
bool BufferLayer::isProtected() const {
- const sp<GraphicBuffer>& activeBuffer(mActiveBuffer);
- return (activeBuffer != 0) && (activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+ const sp<GraphicBuffer>& buffer(getBE().mBuffer);
+ return (buffer != 0) &&
+ (buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
}
bool BufferLayer::isVisible() const {
return !(isHiddenByPolicy()) && getAlpha() > 0.0f &&
- (mActiveBuffer != NULL || getBE().mSidebandStream != NULL);
+ (getBE().mBuffer != NULL || getBE().mSidebandStream != NULL);
}
bool BufferLayer::isFixedSize() const {
@@ -171,7 +172,7 @@
bool useIdentityTransform) const {
ATRACE_CALL();
- if (CC_UNLIKELY(mActiveBuffer == 0)) {
+ if (CC_UNLIKELY(getBE().mBuffer == 0)) {
// the texture has not been created yet, this Layer has
// in fact never been drawn into. This happens frequently with
// SurfaceView because the WindowManager can't know when the client
@@ -249,8 +250,8 @@
}
// Set things up for texturing.
- mTexture.setDimensions(mActiveBuffer->getWidth(),
- mActiveBuffer->getHeight());
+ mTexture.setDimensions(getBE().mBuffer->getWidth(),
+ getBE().mBuffer->getHeight());
mTexture.setFiltering(useFiltering);
mTexture.setMatrix(textureMatrix);
@@ -421,7 +422,7 @@
// Capture the old state of the layer for comparisons later
const State& s(getDrawingState());
const bool oldOpacity = isOpaque(s);
- sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
+ sp<GraphicBuffer> oldBuffer = getBE().mBuffer;
if (!allTransactionsSignaled()) {
mFlinger->signalLayerUpdate();
@@ -498,9 +499,11 @@
}
// update the active buffer
- mActiveBuffer =
- mSurfaceFlingerConsumer->getCurrentBuffer(&mActiveBufferSlot);
- if (mActiveBuffer == NULL) {
+ getBE().mBuffer =
+ mSurfaceFlingerConsumer->getCurrentBuffer(&getBE().mBufferSlot);
+ // replicated in LayerBE until FE/BE is ready to be synchronized
+ mActiveBuffer = getBE().mBuffer;
+ if (getBE().mBuffer == NULL) {
// this can only happen if the very first buffer was rejected.
return outDirtyRegion;
}
@@ -516,7 +519,7 @@
mRefreshPending = true;
mFrameLatencyNeeded = true;
- if (oldActiveBuffer == NULL) {
+ if (oldBuffer == NULL) {
// the first time we receive a buffer, we need to trigger a
// geometry invalidation.
recomputeVisibleRegions = true;
@@ -536,16 +539,16 @@
recomputeVisibleRegions = true;
}
- if (oldActiveBuffer != NULL) {
- uint32_t bufWidth = mActiveBuffer->getWidth();
- uint32_t bufHeight = mActiveBuffer->getHeight();
- if (bufWidth != uint32_t(oldActiveBuffer->width) ||
- bufHeight != uint32_t(oldActiveBuffer->height)) {
+ if (oldBuffer != NULL) {
+ uint32_t bufWidth = getBE().mBuffer->getWidth();
+ uint32_t bufHeight = getBE().mBuffer->getHeight();
+ if (bufWidth != uint32_t(oldBuffer->width) ||
+ bufHeight != uint32_t(oldBuffer->height)) {
recomputeVisibleRegions = true;
}
}
- mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
+ mCurrentOpacity = getOpacityForFormat(getBE().mBuffer->format);
if (oldOpacity != isOpaque(s)) {
recomputeVisibleRegions = true;
}
@@ -638,14 +641,14 @@
uint32_t hwcSlot = 0;
sp<GraphicBuffer> hwcBuffer;
- hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot,
- mActiveBuffer, &hwcSlot, &hwcBuffer);
+ hwcInfo.bufferCache.getHwcBuffer(getBE().mBufferSlot,
+ getBE().mBuffer, &hwcSlot, &hwcBuffer);
auto acquireFence = mSurfaceFlingerConsumer->getCurrentFence();
error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
if (error != HWC2::Error::None) {
ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
- mActiveBuffer->handle, to_string(error).c_str(),
+ getBE().mBuffer->handle, to_string(error).c_str(),
static_cast<int32_t>(error));
}
}
@@ -653,7 +656,7 @@
bool BufferLayer::isOpaque(const Layer::State& s) const {
// if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
// layer's opaque flag.
- if ((getBE().mSidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
+ if ((getBE().mSidebandStream == nullptr) && (getBE().mBuffer == nullptr)) {
return false;
}
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 078302b..1127952 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -32,9 +32,6 @@
#include <gui/ISurfaceComposerClient.h>
#include <gui/LayerState.h>
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
#include <ui/FrameStats.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 6d6781e..2753f11 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -53,12 +53,6 @@
using namespace android;
// ----------------------------------------------------------------------------
-#ifdef EGL_ANDROID_swap_rectangle
-static constexpr bool kEGLAndroidSwapRectangle = true;
-#else
-static constexpr bool kEGLAndroidSwapRectangle = false;
-#endif
-
// retrieve triple buffer setting from configstore
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
@@ -66,12 +60,6 @@
static bool useTripleFramebuffer = getInt64< ISurfaceFlingerConfigs,
&ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2) >= 3;
-#if !defined(EGL_EGLEXT_PROTOTYPES) || !defined(EGL_ANDROID_swap_rectangle)
-// Dummy implementation in case it is missing.
-inline void eglSetSwapRectangleANDROID (EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint) {
-}
-#endif
-
/*
* Initialize the display to the specified values.
*
@@ -88,7 +76,6 @@
const wp<IBinder>& displayToken,
const sp<DisplaySurface>& displaySurface,
const sp<IGraphicBufferProducer>& producer,
- EGLConfig config,
bool supportWideColor)
: lastCompositionHadVisibleLayers(false),
mFlinger(flinger),
@@ -96,11 +83,9 @@
mHwcDisplayId(hwcId),
mDisplayToken(displayToken),
mDisplaySurface(displaySurface),
- mDisplay(EGL_NO_DISPLAY),
- mSurface(EGL_NO_SURFACE),
+ mSurface{flinger->getRenderEngine()},
mDisplayWidth(),
mDisplayHeight(),
- mFlags(),
mPageFlipCount(),
mIsSecure(isSecure),
mLayerStack(NO_LAYER_STACK),
@@ -118,16 +103,11 @@
/*
* Create our display's surface
*/
-
- EGLSurface eglSurface;
- EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- if (config == EGL_NO_CONFIG) {
- config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888,
- /*logConfig*/ false);
- }
- eglSurface = eglCreateWindowSurface(display, config, window, NULL);
- eglQuerySurface(display, eglSurface, EGL_WIDTH, &mDisplayWidth);
- eglQuerySurface(display, eglSurface, EGL_HEIGHT, &mDisplayHeight);
+ mSurface.setCritical(mType == DisplayDevice::DISPLAY_PRIMARY);
+ mSurface.setAsync(mType >= DisplayDevice::DISPLAY_VIRTUAL);
+ mSurface.setNativeWindow(window);
+ mDisplayWidth = mSurface.queryWidth();
+ mDisplayHeight = mSurface.queryHeight();
// Make sure that composition can never be stalled by a virtual display
// consumer that isn't processing buffers fast enough. We have to do this
@@ -139,9 +119,6 @@
if (mType >= DisplayDevice::DISPLAY_VIRTUAL)
window->setSwapInterval(window, 0);
- mConfig = config;
- mDisplay = display;
- mSurface = eglSurface;
mPageFlipCount = 0;
mViewport.makeInvalid();
mFrame.makeInvalid();
@@ -173,10 +150,6 @@
}
DisplayDevice::~DisplayDevice() {
- if (mSurface != EGL_NO_SURFACE) {
- eglDestroySurface(mDisplay, mSurface);
- mSurface = EGL_NO_SURFACE;
- }
}
void DisplayDevice::disconnect(HWComposer& hwc) {
@@ -198,10 +171,6 @@
return mDisplayHeight;
}
-EGLSurface DisplayDevice::getEGLSurface() const {
- return mSurface;
-}
-
void DisplayDevice::setDisplayName(const String8& displayName) {
if (!displayName.isEmpty()) {
// never override the name with an empty name
@@ -213,19 +182,9 @@
return mPageFlipCount;
}
-void DisplayDevice::flip(const Region& dirty) const
+void DisplayDevice::flip() const
{
mFlinger->getRenderEngine().checkErrors();
-
- if (kEGLAndroidSwapRectangle) {
- if (mFlags & SWAP_RECTANGLE) {
- const Region newDirty(dirty.intersect(bounds()));
- const Rect b(newDirty.getBounds());
- eglSetSwapRectangleANDROID(mDisplay, mSurface,
- b.left, b.top, b.width(), b.height());
- }
- }
-
mPageFlipCount++;
}
@@ -259,18 +218,7 @@
void DisplayDevice::swapBuffers(HWComposer& hwc) const {
if (hwc.hasClientComposition(mHwcDisplayId)) {
- EGLBoolean success = eglSwapBuffers(mDisplay, mSurface);
- if (!success) {
- EGLint error = eglGetError();
- if (error == EGL_CONTEXT_LOST ||
- mType == DisplayDevice::DISPLAY_PRIMARY) {
- LOG_ALWAYS_FATAL("eglSwapBuffers(%p, %p) failed with 0x%08x",
- mDisplay, mSurface, error);
- } else {
- ALOGE("eglSwapBuffers(%p, %p) failed with 0x%08x",
- mDisplay, mSurface, error);
- }
- }
+ mSurface.swapBuffers();
}
status_t result = mDisplaySurface->advanceFrame();
@@ -284,23 +232,10 @@
mDisplaySurface->onFrameCommitted();
}
-uint32_t DisplayDevice::getFlags() const
-{
- return mFlags;
-}
-
-EGLBoolean DisplayDevice::makeCurrent(EGLDisplay dpy, EGLContext ctx) const {
- EGLBoolean result = EGL_TRUE;
- EGLSurface sur = eglGetCurrentSurface(EGL_DRAW);
- if (sur != mSurface) {
- result = eglMakeCurrent(dpy, mSurface, mSurface, ctx);
- if (result == EGL_TRUE) {
- if (mType >= DisplayDevice::DISPLAY_VIRTUAL)
- eglSwapInterval(dpy, 0);
- }
- }
+bool DisplayDevice::makeCurrent() const {
+ bool success = mFlinger->getRenderEngine().setCurrentSurface(mSurface);
setViewportAndProjection();
- return result;
+ return success;
}
void DisplayDevice::setViewportAndProjection() const {
@@ -436,17 +371,14 @@
void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) {
dirtyRegion.set(getBounds());
- if (mSurface != EGL_NO_SURFACE) {
- eglDestroySurface(mDisplay, mSurface);
- mSurface = EGL_NO_SURFACE;
- }
+ mSurface.setNativeWindow(nullptr);
mDisplaySurface->resizeBuffers(newWidth, newHeight);
ANativeWindow* const window = mNativeWindow.get();
- mSurface = eglCreateWindowSurface(mDisplay, mConfig, window, NULL);
- eglQuerySurface(mDisplay, mSurface, EGL_WIDTH, &mDisplayWidth);
- eglQuerySurface(mDisplay, mSurface, EGL_HEIGHT, &mDisplayHeight);
+ mSurface.setNativeWindow(window);
+ mDisplayWidth = mSurface.queryWidth();
+ mDisplayHeight = mSurface.queryHeight();
LOG_FATAL_IF(mDisplayWidth != newWidth,
"Unable to set new width to %d", newWidth);
@@ -548,17 +480,13 @@
void DisplayDevice::dump(String8& result) const {
const Transform& tr(mGlobalTransform);
ANativeWindow* const window = mNativeWindow.get();
- EGLint redSize, greenSize, blueSize, alphaSize;
- eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &redSize);
- eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &greenSize);
- eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &blueSize);
- eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &alphaSize);
result.appendFormat("+ DisplayDevice: %s\n", mDisplayName.string());
result.appendFormat(" type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p "
"(%d:%d:%d:%d), orient=%2d (type=%08x), "
"flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n",
mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight, window,
- redSize, greenSize, blueSize, alphaSize, mOrientation, tr.getType(),
+ mSurface.queryRedSize(), mSurface.queryGreenSize(), mSurface.queryBlueSize(),
+ mSurface.queryAlphaSize(), mOrientation, tr.getType(),
getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
mVisibleLayersSortedByZ.size());
result.appendFormat(" v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index e388a5b..499bf8e 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -23,9 +23,6 @@
#include <ui/Region.h>
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
#include <binder/IBinder.h>
#include <utils/RefBase.h>
#include <utils/Mutex.h>
@@ -35,6 +32,7 @@
#include <gui/ISurfaceComposer.h>
#include <hardware/hwcomposer_defs.h>
#include "RenderArea.h"
+#include "RenderEngine/Surface.h"
#include <memory>
@@ -56,8 +54,6 @@
// region in layer-stack space
mutable Region dirtyRegion;
// region in screen space
- mutable Region swapRegion;
- // region in screen space
Region undefinedRegion;
bool lastCompositionHadVisibleLayers;
@@ -70,11 +66,6 @@
};
enum {
- PARTIAL_UPDATES = 0x00020000, // video driver feature
- SWAP_RECTANGLE = 0x00080000,
- };
-
- enum {
NO_LAYER_STACK = 0xFFFFFFFF,
};
@@ -87,7 +78,6 @@
const wp<IBinder>& displayToken,
const sp<DisplaySurface>& displaySurface,
const sp<IGraphicBufferProducer>& producer,
- EGLConfig config,
bool supportWideColor);
// clang-format on
@@ -103,13 +93,10 @@
// 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 Region& dirty) const;
+ void flip() const;
int getWidth() const;
int getHeight() const;
- uint32_t getFlags() const;
-
- EGLSurface getEGLSurface() const;
void setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers);
const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const;
@@ -155,7 +142,7 @@
void setDisplayName(const String8& displayName);
const String8& getDisplayName() const { return mDisplayName; }
- EGLBoolean makeCurrent(EGLDisplay dpy, EGLContext ctx) const;
+ bool makeCurrent() const;
void setViewportAndProjection() const;
const sp<Fence>& getClientTargetAcquireFence() const;
@@ -199,12 +186,9 @@
sp<ANativeWindow> mNativeWindow;
sp<DisplaySurface> mDisplaySurface;
- EGLConfig mConfig;
- EGLDisplay mDisplay;
- EGLSurface mSurface;
+ RE::Surface mSurface;
int mDisplayWidth;
int mDisplayHeight;
- uint32_t mFlags;
mutable uint32_t mPageFlipCount;
String8 mDisplayName;
bool mIsSecure;
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 182629c..8b5d4c9 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -27,8 +27,6 @@
#include <utils/String8.h>
#include <log/log.h>
-#include <EGL/egl.h>
-
#include <hardware/hardware.h>
#include <gui/BufferItem.h>
#include <gui/BufferQueue.h>
@@ -164,8 +162,7 @@
ALOGE_IF(result != NO_ERROR, "onFrameCommitted: failed to add the"
" fence: %s (%d)", strerror(-result), result);
}
- status_t result = releaseBufferLocked(mPreviousBufferSlot,
- mPreviousBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+ status_t result = releaseBufferLocked(mPreviousBufferSlot, mPreviousBuffer);
ALOGE_IF(result != NO_ERROR, "onFrameCommitted: error releasing buffer:"
" %s (%d)", strerror(-result), result);
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index dba6f7c..cde96e4 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -244,8 +244,7 @@
VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot);
addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot],
retireFence);
- releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot],
- EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+ releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot]);
}
if (mOutputProducerSlot >= 0) {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 359b64f..2a4abcb 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -63,7 +63,9 @@
namespace android {
LayerBE::LayerBE()
- : mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2) {
+ : mBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
+ mBuffer(nullptr),
+ mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2) {
}
@@ -255,9 +257,9 @@
if (!mCurrentCrop.isEmpty()) {
// if the buffer crop is defined, we use that
crop = mCurrentCrop;
- } else if (mActiveBuffer != NULL) {
+ } else if (getBE().mBuffer != NULL) {
// otherwise we use the whole buffer
- crop = mActiveBuffer->getBounds();
+ crop = getBE().mBuffer->getBounds();
} else {
// if we don't have a buffer yet, we use an empty/invalid crop
crop.makeInvalid();
@@ -1000,7 +1002,7 @@
// to the old buffer. However in the state where we don't have an old buffer
// there is no such concern but we may still be being used as a parent layer.
const bool resizePending = ((c.requested.w != c.active.w) || (c.requested.h != c.active.h)) &&
- (mActiveBuffer != nullptr);
+ (getBE().mBuffer != nullptr);
if (!isFixedSize()) {
if (resizePending && getBE().mSidebandStream == NULL) {
flags |= eDontUpdateGeometryState;
@@ -1399,12 +1401,12 @@
info.mMatrix[1][0] = ds.active.transform[1][0];
info.mMatrix[1][1] = ds.active.transform[1][1];
{
- sp<const GraphicBuffer> activeBuffer = getActiveBuffer();
- if (activeBuffer != 0) {
- info.mActiveBufferWidth = activeBuffer->getWidth();
- info.mActiveBufferHeight = activeBuffer->getHeight();
- info.mActiveBufferStride = activeBuffer->getStride();
- info.mActiveBufferFormat = activeBuffer->format;
+ sp<const GraphicBuffer> buffer = getBE().mBuffer;
+ if (buffer != 0) {
+ info.mActiveBufferWidth = buffer->getWidth();
+ info.mActiveBufferHeight = buffer->getHeight();
+ info.mActiveBufferStride = buffer->getStride();
+ info.mActiveBufferFormat = buffer->format;
} else {
info.mActiveBufferWidth = 0;
info.mActiveBufferHeight = 0;
@@ -1718,15 +1720,15 @@
// for in the transform. We need to mirror this scaling in child surfaces
// or we will break the contract where WM can treat child surfaces as
// pixels in the parent surface.
- if (p->isFixedSize() && p->mActiveBuffer != nullptr) {
+ if (p->isFixedSize() && p->getBE().mBuffer != nullptr) {
int bufferWidth;
int bufferHeight;
if ((p->mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) == 0) {
- bufferWidth = p->mActiveBuffer->getWidth();
- bufferHeight = p->mActiveBuffer->getHeight();
+ bufferWidth = p->getBE().mBuffer->getWidth();
+ bufferHeight = p->getBE().mBuffer->getHeight();
} else {
- bufferHeight = p->mActiveBuffer->getWidth();
- bufferWidth = p->mActiveBuffer->getHeight();
+ bufferHeight = p->getBE().mBuffer->getWidth();
+ bufferWidth = p->getBE().mBuffer->getHeight();
}
float sx = p->getDrawingState().active.w / static_cast<float>(bufferWidth);
float sy = p->getDrawingState().active.h / static_cast<float>(bufferHeight);
@@ -1826,9 +1828,9 @@
layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence);
}
- auto activeBuffer = getActiveBuffer();
- if (activeBuffer != nullptr) {
- LayerProtoHelper::writeToProto(activeBuffer, layerInfo->mutable_active_buffer());
+ auto buffer = getBE().mBuffer;
+ if (buffer != nullptr) {
+ LayerProtoHelper::writeToProto(buffer, layerInfo->mutable_active_buffer());
}
layerInfo->set_queued_frames(getQueuedFrameCount());
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index b7b7a3a..8ac5094 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -20,9 +20,6 @@
#include <stdint.h>
#include <sys/types.h>
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <utils/Timers.h>
@@ -73,6 +70,9 @@
public:
LayerBE();
+ // main thread
+ int mBufferSlot;
+ sp<GraphicBuffer> mBuffer;
sp<NativeHandle> mSidebandStream;
// The mesh used to draw the layer in GLES composition mode
@@ -472,8 +472,6 @@
void setFiltering(bool filtering);
bool getFiltering() const;
- // only for debugging
- inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
inline const State& getDrawingState() const { return mDrawingState; }
inline const State& getCurrentState() const { return mCurrentState; }
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 44b9dc9..fa4df83 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -6,7 +6,8 @@
class RenderArea {
public:
- RenderArea(uint32_t reqHeight, uint32_t reqWidth, ISurfaceComposer::Rotation rotation)
+ RenderArea(uint32_t reqHeight, uint32_t reqWidth,
+ ISurfaceComposer::Rotation rotation = ISurfaceComposer::eRotateNone)
: mReqHeight(reqHeight), mReqWidth(reqWidth) {
mRotationFlags = Transform::fromRotation(rotation);
}
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index 706960c..e014406 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -33,8 +33,7 @@
mColorMatrixEnabled = false;
}
-Description::~Description() {
-}
+Description::~Description() {}
void Description::setPremultipliedAlpha(bool premultipliedAlpha) {
mPremultipliedAlpha = premultipliedAlpha;
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 3ae7042..3161888 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -33,15 +33,15 @@
#include <gui/ISurfaceComposer.h>
#include <math.h>
+#include "Description.h"
#include "GLES20RenderEngine.h"
+#include "Mesh.h"
#include "Program.h"
#include "ProgramCache.h"
-#include "Description.h"
-#include "Mesh.h"
#include "Texture.h"
-#include <sstream>
#include <fstream>
+#include <sstream>
// ---------------------------------------------------------------------------
bool checkGlError(const char* op, int lineNumber) {
@@ -107,34 +107,31 @@
namespace android {
// ---------------------------------------------------------------------------
-GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags) :
- mVpWidth(0),
- mVpHeight(0),
- mPlatformHasWideColor((featureFlags & WIDE_COLOR_SUPPORT) != 0) {
-
+GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags)
+ : mVpWidth(0), mVpHeight(0), mPlatformHasWideColor((featureFlags & WIDE_COLOR_SUPPORT) != 0) {
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
- const uint16_t protTexData[] = { 0 };
+ const uint16_t protTexData[] = {0};
glGenTextures(1, &mProtectedTexName);
glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0,
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
- //mColorBlindnessCorrection = M;
+ // mColorBlindnessCorrection = M;
if (mPlatformHasWideColor) {
// Compute sRGB to DisplayP3 color transform
// NOTE: For now, we are limiting wide-color support to
// Display-P3 only.
- mat3 srgbToP3 = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::DisplayP3()).getTransform();
+ mat3 srgbToP3 =
+ ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::DisplayP3()).getTransform();
// color transform needs to be expanded to 4x4 to be what the shader wants
// mat has an initializer that expands mat3 to mat4, but
@@ -144,24 +141,19 @@
}
}
-GLES20RenderEngine::~GLES20RenderEngine() {
-}
-
+GLES20RenderEngine::~GLES20RenderEngine() {}
size_t GLES20RenderEngine::getMaxTextureSize() const {
return mMaxTextureSize;
}
size_t GLES20RenderEngine::getMaxViewportDims() const {
- return
- mMaxViewportDims[0] < mMaxViewportDims[1] ?
- mMaxViewportDims[0] : mMaxViewportDims[1];
+ return mMaxViewportDims[0] < mMaxViewportDims[1] ? mMaxViewportDims[0] : mMaxViewportDims[1];
}
-void GLES20RenderEngine::setViewportAndProjection(
- size_t vpw, size_t vph, Rect sourceCrop, size_t hwh, bool yswap,
- Transform::orientation_flags rotation) {
-
+void GLES20RenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
+ size_t hwh, bool yswap,
+ Transform::orientation_flags rotation) {
size_t l = sourceCrop.left;
size_t r = sourceCrop.right;
@@ -182,13 +174,13 @@
case Transform::ROT_0:
break;
case Transform::ROT_90:
- m = mat4::rotate(rot90InRadians, vec3(0,0,1)) * m;
+ m = mat4::rotate(rot90InRadians, vec3(0, 0, 1)) * m;
break;
case Transform::ROT_180:
- m = mat4::rotate(rot90InRadians * 2.0f, vec3(0,0,1)) * m;
+ m = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)) * m;
break;
case Transform::ROT_270:
- m = mat4::rotate(rot90InRadians * 3.0f, vec3(0,0,1)) * m;
+ m = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)) * m;
break;
default:
break;
@@ -200,8 +192,8 @@
mVpHeight = vph;
}
-void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha,
- bool opaque, bool disableTexture, const half4& color) {
+void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque,
+ bool disableTexture, const half4& color) {
mState.setPremultipliedAlpha(premultipliedAlpha);
mState.setOpaque(opaque);
mState.setColor(color);
@@ -288,9 +280,8 @@
glDisable(GL_BLEND);
}
-
-void GLES20RenderEngine::bindImageAsFramebuffer(EGLImageKHR image,
- uint32_t* texName, uint32_t* fbName, uint32_t* status) {
+void GLES20RenderEngine::bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName,
+ uint32_t* fbName, uint32_t* status) {
GLuint tname, name;
// turn our EGLImage into a texture
glGenTextures(1, &tname);
@@ -322,21 +313,14 @@
}
void GLES20RenderEngine::drawMesh(const Mesh& mesh) {
-
if (mesh.getTexCoordsSize()) {
glEnableVertexAttribArray(Program::texCoords);
- glVertexAttribPointer(Program::texCoords,
- mesh.getTexCoordsSize(),
- GL_FLOAT, GL_FALSE,
- mesh.getByteStride(),
- mesh.getTexCoords());
+ glVertexAttribPointer(Program::texCoords, mesh.getTexCoordsSize(), GL_FLOAT, GL_FALSE,
+ mesh.getByteStride(), mesh.getTexCoords());
}
- glVertexAttribPointer(Program::position,
- mesh.getVertexSize(),
- GL_FLOAT, GL_FALSE,
- mesh.getByteStride(),
- mesh.getPositions());
+ glVertexAttribPointer(Program::position, mesh.getVertexSize(), GL_FLOAT, GL_FALSE,
+ mesh.getByteStride(), mesh.getPositions());
if (usesWideColor()) {
Description wideColorState = mState;
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index b96bfe0..5ee9326 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
#ifndef SF_GLES20RENDERENGINE_H_
#define SF_GLES20RENDERENGINE_H_
@@ -24,9 +23,9 @@
#include <GLES2/gl2.h>
#include <Transform.h>
-#include "RenderEngine.h"
-#include "ProgramCache.h"
#include "Description.h"
+#include "ProgramCache.h"
+#include "RenderEngine.h"
// ---------------------------------------------------------------------------
namespace android {
@@ -54,22 +53,20 @@
Description mState;
Vector<Group> mGroupStack;
- virtual void bindImageAsFramebuffer(EGLImageKHR image,
- uint32_t* texName, uint32_t* fbName, uint32_t* status);
+ virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName,
+ uint32_t* status);
virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName);
public:
GLES20RenderEngine(uint32_t featureFlags); // See RenderEngine::FeatureFlag
-
-protected:
virtual ~GLES20RenderEngine();
+protected:
virtual void dump(String8& result);
- virtual void setViewportAndProjection(size_t vpw, size_t vph,
- Rect sourceCrop, size_t hwh, bool yswap,
- Transform::orientation_flags rotation);
- virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
- bool disableTexture, const half4& color) override;
+ virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh,
+ bool yswap, Transform::orientation_flags rotation);
+ virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
+ const half4& color) override;
// Color management related functions and state
void setColorMode(android_color_mode mode);
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.cpp b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
index 76bbcc1..7ffcc96 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.cpp
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
@@ -14,42 +14,35 @@
* limitations under the License.
*/
-#include <stdlib.h>
-#include <stdio.h>
#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
#include "GLExtensions.h"
namespace android {
// ---------------------------------------------------------------------------
-ANDROID_SINGLETON_STATIC_INSTANCE( GLExtensions )
+ANDROID_SINGLETON_STATIC_INSTANCE(GLExtensions)
-GLExtensions::GLExtensions()
- : mHaveFramebufferObject(false)
-{
-}
+GLExtensions::GLExtensions() : mHaveFramebufferObject(false) {}
-void GLExtensions::initWithGLStrings(
- GLubyte const* vendor,
- GLubyte const* renderer,
- GLubyte const* version,
- GLubyte const* extensions)
-{
- mVendor = (char const*)vendor;
- mRenderer = (char const*)renderer;
- mVersion = (char const*)version;
+void GLExtensions::initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer,
+ GLubyte const* version, GLubyte const* extensions) {
+ mVendor = (char const*)vendor;
+ mRenderer = (char const*)renderer;
+ mVersion = (char const*)version;
mExtensions = (char const*)extensions;
char const* curr = (char const*)extensions;
char const* head = curr;
do {
head = strchr(curr, ' ');
- String8 s(curr, head ? head-curr : strlen(curr));
+ String8 s(curr, head ? head - curr : strlen(curr));
if (s.length()) {
mExtensionList.add(s);
}
- curr = head+1;
+ curr = head + 1;
} while (head);
if (hasExtension("GL_OES_framebuffer_object")) {
@@ -57,8 +50,7 @@
}
}
-bool GLExtensions::hasExtension(char const* extension) const
-{
+bool GLExtensions::hasExtension(char const* extension) const {
const String8 s(extension);
return mExtensionList.indexOf(s) >= 0;
}
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.h b/services/surfaceflinger/RenderEngine/GLExtensions.h
index d81ed2a..ee7b446 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.h
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.h
@@ -20,9 +20,9 @@
#include <stdint.h>
#include <sys/types.h>
-#include <utils/String8.h>
-#include <utils/SortedVector.h>
#include <utils/Singleton.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
@@ -32,8 +32,7 @@
namespace android {
// ---------------------------------------------------------------------------
-class GLExtensions : public Singleton<GLExtensions>
-{
+class GLExtensions : public Singleton<GLExtensions> {
friend class Singleton<GLExtensions>;
bool mHaveFramebufferObject : 1;
@@ -45,22 +44,16 @@
SortedVector<String8> mExtensionList;
GLExtensions(const GLExtensions&);
- GLExtensions& operator = (const GLExtensions&);
+ GLExtensions& operator=(const GLExtensions&);
protected:
GLExtensions();
public:
+ inline bool haveFramebufferObject() const { return mHaveFramebufferObject; }
- inline bool haveFramebufferObject() const {
- return mHaveFramebufferObject;
- }
-
- void initWithGLStrings(
- GLubyte const* vendor,
- GLubyte const* renderer,
- GLubyte const* version,
- GLubyte const* extensions);
+ void initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer, GLubyte const* version,
+ GLubyte const* extensions);
char const* getVendor() const;
char const* getRenderer() const;
@@ -70,7 +63,6 @@
bool hasExtension(char const* extension) const;
};
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/services/surfaceflinger/RenderEngine/Mesh.cpp
index ffd9be2..6a62b1d 100644
--- a/services/surfaceflinger/RenderEngine/Mesh.cpp
+++ b/services/surfaceflinger/RenderEngine/Mesh.cpp
@@ -21,9 +21,10 @@
namespace android {
Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize)
- : mVertexCount(vertexCount), mVertexSize(vertexSize), mTexCoordsSize(texCoordSize),
- mPrimitive(primitive)
-{
+ : mVertexCount(vertexCount),
+ mVertexSize(vertexSize),
+ mTexCoordsSize(texCoordSize),
+ mPrimitive(primitive) {
if (vertexCount == 0) {
mVertices = new float[1];
mVertices[0] = 0.0f;
@@ -37,8 +38,7 @@
// either vertexSize or texCoordSize, it must have overflowed. remainder
// will be equal to stride as long as stride * vertexCount doesn't overflow.
if ((stride < vertexSize) || (remainder != stride)) {
- ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize,
- texCoordSize);
+ ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize, texCoordSize);
mVertices = new float[1];
mVertices[0] = 0.0f;
mVertexCount = 0;
@@ -53,14 +53,13 @@
}
Mesh::~Mesh() {
- delete [] mVertices;
+ delete[] mVertices;
}
Mesh::Primitive Mesh::getPrimitive() const {
return mPrimitive;
}
-
float const* Mesh::getPositions() const {
return mVertices;
}
@@ -75,7 +74,6 @@
return mVertices + mVertexSize;
}
-
size_t Mesh::getVertexCount() const {
return mVertexCount;
}
@@ -89,7 +87,7 @@
}
size_t Mesh::getByteStride() const {
- return mStride*sizeof(float);
+ return mStride * sizeof(float);
}
size_t Mesh::getStride() const {
diff --git a/services/surfaceflinger/RenderEngine/Mesh.h b/services/surfaceflinger/RenderEngine/Mesh.h
index b6d42b0..d0a9ac0 100644
--- a/services/surfaceflinger/RenderEngine/Mesh.h
+++ b/services/surfaceflinger/RenderEngine/Mesh.h
@@ -24,9 +24,9 @@
class Mesh {
public:
enum Primitive {
- TRIANGLES = 0x0004, // GL_TRIANGLES
- TRIANGLE_STRIP = 0x0005, // GL_TRIANGLE_STRIP
- TRIANGLE_FAN = 0x0006 // GL_TRIANGLE_FAN
+ TRIANGLES = 0x0004, // GL_TRIANGLES
+ TRIANGLE_STRIP = 0x0005, // GL_TRIANGLE_STRIP
+ TRIANGLE_FAN = 0x0006 // GL_TRIANGLE_FAN
};
Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordsSize = 0);
@@ -40,21 +40,24 @@
friend class Mesh;
float* mData;
size_t mStride;
- VertexArray(float* data, size_t stride) : mData(data), mStride(stride) { }
+ VertexArray(float* data, size_t stride) : mData(data), mStride(stride) {}
+
public:
- TYPE& operator[](size_t index) {
- return *reinterpret_cast<TYPE*>(&mData[index*mStride]);
- }
+ TYPE& operator[](size_t index) { return *reinterpret_cast<TYPE*>(&mData[index * mStride]); }
TYPE const& operator[](size_t index) const {
- return *reinterpret_cast<TYPE const*>(&mData[index*mStride]);
+ return *reinterpret_cast<TYPE const*>(&mData[index * mStride]);
}
};
template <typename TYPE>
- VertexArray<TYPE> getPositionArray() { return VertexArray<TYPE>(getPositions(), mStride); }
+ VertexArray<TYPE> getPositionArray() {
+ return VertexArray<TYPE>(getPositions(), mStride);
+ }
template <typename TYPE>
- VertexArray<TYPE> getTexCoordArray() { return VertexArray<TYPE>(getTexCoords(), mStride); }
+ VertexArray<TYPE> getTexCoordArray() {
+ return VertexArray<TYPE>(getTexCoords(), mStride);
+ }
Primitive getPrimitive() const;
@@ -81,8 +84,8 @@
private:
Mesh(const Mesh&);
- Mesh& operator = (const Mesh&);
- Mesh const& operator = (const Mesh&) const;
+ Mesh& operator=(const Mesh&);
+ Mesh const& operator=(const Mesh&) const;
float* getPositions();
float* getTexCoords();
@@ -94,6 +97,5 @@
Primitive mPrimitive;
};
-
} /* namespace android */
#endif /* SF_RENDER_ENGINE_MESH_H */
diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/Program.cpp
index bd2188b..baf92eb 100644
--- a/services/surfaceflinger/RenderEngine/Program.cpp
+++ b/services/surfaceflinger/RenderEngine/Program.cpp
@@ -19,15 +19,15 @@
#include <log/log.h>
#include <utils/String8.h>
+#include <math/mat4.h>
+#include "Description.h"
#include "Program.h"
#include "ProgramCache.h"
-#include "Description.h"
-#include <math/mat4.h>
namespace android {
Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const char* fragment)
- : mInitialized(false) {
+ : mInitialized(false) {
GLuint vertexId = buildShader(vertex, GL_VERTEX_SHADER);
GLuint fragmentId = buildShader(fragment, GL_FRAGMENT_SHADER);
GLuint programId = glCreateProgram();
@@ -67,14 +67,12 @@
// set-up the default values for our uniforms
glUseProgram(programId);
- const GLfloat m[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };
- glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, m);
+ glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, mat4().asArray());
glEnableVertexAttribArray(0);
}
}
-Program::~Program() {
-}
+Program::~Program() {}
bool Program::isValid() const {
return mInitialized;
@@ -119,12 +117,11 @@
char* src = new char[l];
glGetShaderSource(shader, l, NULL, src);
result.append(src);
- delete [] src;
+ delete[] src;
return result;
}
void Program::setUniforms(const Description& desc) {
-
// TODO: we should have a mechanism here to not always reset uniforms that
// didn't change for this program.
diff --git a/services/surfaceflinger/RenderEngine/Program.h b/services/surfaceflinger/RenderEngine/Program.h
index a2ae2ee..6e57fdd 100644
--- a/services/surfaceflinger/RenderEngine/Program.h
+++ b/services/surfaceflinger/RenderEngine/Program.h
@@ -34,7 +34,7 @@
class Program {
public:
// known locations for position and texture coordinates
- enum { position=0, texCoords=1 };
+ enum { position = 0, texCoords = 1 };
Program(const ProgramCache::Key& needs, const char* vertex, const char* fragment);
~Program();
@@ -54,7 +54,6 @@
/* set-up uniforms from the description */
void setUniforms(const Description& desc);
-
private:
GLuint buildShader(const char* source, GLenum type);
String8& dumpShader(String8& result, GLenum type);
@@ -83,7 +82,6 @@
GLint mColorLoc;
};
-
} /* namespace android */
#endif /* SF_RENDER_ENGINE_PROGRAM_H */
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index b437545..4f138dc 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -19,14 +19,13 @@
#include <utils/String8.h>
-#include "ProgramCache.h"
-#include "Program.h"
#include "Description.h"
+#include "Program.h"
+#include "ProgramCache.h"
namespace android {
// -----------------------------------------------------------------------------------------------
-
/*
* A simple formatter class to automatically add the endl and
* manage the indentation.
@@ -42,23 +41,22 @@
typedef Formatter& (*FormaterManipFunc)(Formatter&);
friend Formatter& indent(Formatter& f);
friend Formatter& dedent(Formatter& f);
+
public:
Formatter() : mIndent(0) {}
- String8 getString() const {
- return mString;
- }
+ String8 getString() const { return mString; }
- friend Formatter& operator << (Formatter& out, const char* in) {
- for (int i=0 ; i<out.mIndent ; i++) {
+ friend Formatter& operator<<(Formatter& out, const char* in) {
+ for (int i = 0; i < out.mIndent; i++) {
out.mString.append(" ");
}
out.mString.append(in);
out.mString.append("\n");
return out;
}
- friend inline Formatter& operator << (Formatter& out, const String8& in) {
- return operator << (out, in.string());
+ friend inline Formatter& operator<<(Formatter& out, const String8& in) {
+ return operator<<(out, in.string());
}
friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) {
return (*func)(to);
@@ -83,13 +81,11 @@
primeCache();
}
-ProgramCache::~ProgramCache() {
-}
+ProgramCache::~ProgramCache() {}
void ProgramCache::primeCache() {
uint32_t shaderCount = 0;
- uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK |
- Key::ALPHA_MASK | Key::TEXTURE_MASK;
+ uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK;
// Prime the cache for all combinations of the above masks,
// leaving off the experimental color matrix mask options.
@@ -98,9 +94,7 @@
Key shaderKey;
shaderKey.set(keyMask, keyVal);
uint32_t tex = shaderKey.getTextureTarget();
- if (tex != Key::TEXTURE_OFF &&
- tex != Key::TEXTURE_EXT &&
- tex != Key::TEXTURE_2D) {
+ if (tex != Key::TEXTURE_OFF && tex != Key::TEXTURE_EXT && tex != Key::TEXTURE_2D) {
continue;
}
Program* program = mCache.valueFor(shaderKey);
@@ -118,34 +112,36 @@
ProgramCache::Key ProgramCache::computeKey(const Description& description) {
Key needs;
needs.set(Key::TEXTURE_MASK,
- !description.mTextureEnabled ? Key::TEXTURE_OFF :
- description.mTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES ? Key::TEXTURE_EXT :
- description.mTexture.getTextureTarget() == GL_TEXTURE_2D ? Key::TEXTURE_2D :
- Key::TEXTURE_OFF)
- .set(Key::ALPHA_MASK,
- (description.mColor.a < 1) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE)
- .set(Key::BLEND_MASK,
- description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL)
- .set(Key::OPACITY_MASK,
- description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT)
- .set(Key::COLOR_MATRIX_MASK,
- description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON : Key::COLOR_MATRIX_OFF)
- .set(Key::WIDE_GAMUT_MASK,
- description.mIsWideGamut ? Key::WIDE_GAMUT_ON : Key::WIDE_GAMUT_OFF);
+ !description.mTextureEnabled
+ ? Key::TEXTURE_OFF
+ : description.mTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES
+ ? Key::TEXTURE_EXT
+ : description.mTexture.getTextureTarget() == GL_TEXTURE_2D
+ ? Key::TEXTURE_2D
+ : Key::TEXTURE_OFF)
+ .set(Key::ALPHA_MASK,
+ (description.mColor.a < 1) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE)
+ .set(Key::BLEND_MASK,
+ description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL)
+ .set(Key::OPACITY_MASK,
+ description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT)
+ .set(Key::COLOR_MATRIX_MASK,
+ description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON : Key::COLOR_MATRIX_OFF)
+ .set(Key::WIDE_GAMUT_MASK,
+ description.mIsWideGamut ? Key::WIDE_GAMUT_ON : Key::WIDE_GAMUT_OFF);
return needs;
}
String8 ProgramCache::generateVertexShader(const Key& needs) {
Formatter vs;
if (needs.isTexturing()) {
- vs << "attribute vec4 texCoords;"
- << "varying vec2 outTexCoords;";
+ vs << "attribute vec4 texCoords;"
+ << "varying vec2 outTexCoords;";
}
vs << "attribute vec4 position;"
<< "uniform mat4 projection;"
<< "uniform mat4 texture;"
- << "void main(void) {" << indent
- << "gl_Position = projection * position;";
+ << "void main(void) {" << indent << "gl_Position = projection * position;";
if (needs.isTexturing()) {
vs << "outTexCoords = (texture * texCoords).st;";
}
@@ -272,11 +268,10 @@
}
void ProgramCache::useProgram(const Description& description) {
-
// generate the key for the shader based on the description
Key needs(computeKey(description));
- // look-up the program in the cache
+ // look-up the program in the cache
Program* program = mCache.valueFor(needs);
if (program == NULL) {
// we didn't find our program, so generate one...
@@ -285,7 +280,7 @@
mCache.add(needs, program);
time += systemTime();
- //ALOGD(">>> generated new program: needs=%08X, time=%u ms (%d programs)",
+ // ALOGD(">>> generated new program: needs=%08X, time=%u ms (%d programs)",
// needs.mNeeds, uint32_t(ns2ms(time)), mCache.size());
}
@@ -296,5 +291,4 @@
}
}
-
} /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h
index ff5cf0f..54d3722 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.h
@@ -19,8 +19,8 @@
#include <GLES2/gl2.h>
-#include <utils/Singleton.h>
#include <utils/KeyedVector.h>
+#include <utils/Singleton.h>
#include <utils/TypeHelpers.h>
#include "Description.h"
@@ -47,63 +47,50 @@
friend class ProgramCache;
typedef uint32_t key_t;
key_t mKey;
+
public:
enum {
- BLEND_PREMULT = 0x00000001,
- BLEND_NORMAL = 0x00000000,
- BLEND_MASK = 0x00000001,
+ BLEND_PREMULT = 0x00000001,
+ BLEND_NORMAL = 0x00000000,
+ BLEND_MASK = 0x00000001,
- OPACITY_OPAQUE = 0x00000002,
- OPACITY_TRANSLUCENT = 0x00000000,
- OPACITY_MASK = 0x00000002,
+ OPACITY_OPAQUE = 0x00000002,
+ OPACITY_TRANSLUCENT = 0x00000000,
+ OPACITY_MASK = 0x00000002,
- ALPHA_LT_ONE = 0x00000004,
- ALPHA_EQ_ONE = 0x00000000,
- ALPHA_MASK = 0x00000004,
+ ALPHA_LT_ONE = 0x00000004,
+ ALPHA_EQ_ONE = 0x00000000,
+ ALPHA_MASK = 0x00000004,
- TEXTURE_OFF = 0x00000000,
- TEXTURE_EXT = 0x00000008,
- TEXTURE_2D = 0x00000010,
- TEXTURE_MASK = 0x00000018,
+ TEXTURE_OFF = 0x00000000,
+ TEXTURE_EXT = 0x00000008,
+ TEXTURE_2D = 0x00000010,
+ TEXTURE_MASK = 0x00000018,
- COLOR_MATRIX_OFF = 0x00000000,
- COLOR_MATRIX_ON = 0x00000020,
- COLOR_MATRIX_MASK = 0x00000020,
+ COLOR_MATRIX_OFF = 0x00000000,
+ COLOR_MATRIX_ON = 0x00000020,
+ COLOR_MATRIX_MASK = 0x00000020,
- WIDE_GAMUT_OFF = 0x00000000,
- WIDE_GAMUT_ON = 0x00000040,
- WIDE_GAMUT_MASK = 0x00000040,
+ WIDE_GAMUT_OFF = 0x00000000,
+ WIDE_GAMUT_ON = 0x00000040,
+ WIDE_GAMUT_MASK = 0x00000040,
};
- inline Key() : mKey(0) { }
- inline Key(const Key& rhs) : mKey(rhs.mKey) { }
+ inline Key() : mKey(0) {}
+ inline Key(const Key& rhs) : mKey(rhs.mKey) {}
inline Key& set(key_t mask, key_t value) {
mKey = (mKey & ~mask) | value;
return *this;
}
- inline bool isTexturing() const {
- return (mKey & TEXTURE_MASK) != TEXTURE_OFF;
- }
- inline int getTextureTarget() const {
- return (mKey & TEXTURE_MASK);
- }
- inline bool isPremultiplied() const {
- return (mKey & BLEND_MASK) == BLEND_PREMULT;
- }
- inline bool isOpaque() const {
- return (mKey & OPACITY_MASK) == OPACITY_OPAQUE;
- }
- inline bool hasAlpha() const {
- return (mKey & ALPHA_MASK) == ALPHA_LT_ONE;
- }
- inline bool hasColorMatrix() const {
- return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON;
- }
- inline bool isWideGamut() const {
- return (mKey & WIDE_GAMUT_MASK) == WIDE_GAMUT_ON;
- }
+ inline bool isTexturing() const { return (mKey & TEXTURE_MASK) != TEXTURE_OFF; }
+ inline int getTextureTarget() const { return (mKey & TEXTURE_MASK); }
+ inline bool isPremultiplied() const { return (mKey & BLEND_MASK) == BLEND_PREMULT; }
+ inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; }
+ inline bool hasAlpha() const { return (mKey & ALPHA_MASK) == ALPHA_LT_ONE; }
+ inline bool hasColorMatrix() const { return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON; }
+ inline bool isWideGamut() const { return (mKey & WIDE_GAMUT_MASK) == WIDE_GAMUT_ON; }
// this is the definition of a friend function -- not a method of class Needs
friend inline int strictly_order_type(const Key& lhs, const Key& rhs) {
@@ -135,7 +122,6 @@
DefaultKeyedVector<Key, Program*> mCache;
};
-
ANDROID_BASIC_TYPES_TRAITS(ProgramCache::Key)
} /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 56e9ac0..883ae26 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -18,13 +18,13 @@
#include <ui/Rect.h>
#include <ui/Region.h>
-#include "RenderEngine.h"
#include "GLES20RenderEngine.h"
#include "GLExtensions.h"
#include "Mesh.h"
+#include "RenderEngine.h"
-#include <vector>
#include <SurfaceFlinger.h>
+#include <vector>
extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
@@ -33,21 +33,25 @@
// ---------------------------------------------------------------------------
static bool findExtension(const char* exts, const char* name) {
- if (!exts)
- return false;
+ if (!exts) return false;
size_t len = strlen(name);
const char* pos = exts;
while ((pos = strstr(pos, name)) != NULL) {
- if (pos[len] == '\0' || pos[len] == ' ')
- return true;
+ if (pos[len] == '\0' || pos[len] == ' ') return true;
pos += len;
}
return false;
}
-RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t featureFlags) {
+std::unique_ptr<RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags) {
+ // initialize EGL for the default display
+ EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (!eglInitialize(display, NULL, NULL)) {
+ LOG_ALWAYS_FATAL("failed to initialize EGL");
+ }
+
// EGL_ANDROIDX_no_config_context is an experimental extension with no
// written specification. It will be replaced by something more formal.
// SurfaceFlinger is using it to allow a single EGLContext to render to
@@ -70,8 +74,7 @@
EGLint renderableType = 0;
if (config == EGL_NO_CONFIG) {
renderableType = EGL_OPENGL_ES2_BIT;
- } else if (!eglGetConfigAttrib(display, config,
- EGL_RENDERABLE_TYPE, &renderableType)) {
+ } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) {
LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");
}
EGLint contextClientVersion = 0;
@@ -96,12 +99,10 @@
contextAttributes.push_back(EGL_NONE);
contextAttributes.push_back(EGL_NONE);
- EGLContext ctxt = eglCreateContext(display, config, NULL,
- contextAttributes.data());
+ EGLContext ctxt = eglCreateContext(display, config, NULL, contextAttributes.data());
// if can't create a GL context, we can only abort.
- LOG_ALWAYS_FATAL_IF(ctxt==EGL_NO_CONTEXT, "EGLContext creation failed");
-
+ LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
// now figure out what version of GL did we actually get
// NOTE: a dummy surface is not needed if KHR_create_context is supported
@@ -110,35 +111,32 @@
if (dummyConfig == EGL_NO_CONFIG) {
dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
}
- EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE };
+ EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE};
EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs);
- LOG_ALWAYS_FATAL_IF(dummy==EGL_NO_SURFACE, "can't create dummy pbuffer");
+ LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");
GLExtensions& extensions(GLExtensions::getInstance());
- extensions.initWithGLStrings(
- glGetString(GL_VENDOR),
- glGetString(GL_RENDERER),
- glGetString(GL_VERSION),
- glGetString(GL_EXTENSIONS));
+ extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
+ glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
- GlesVersion version = parseGlesVersion( extensions.getVersion() );
+ GlesVersion version = parseGlesVersion(extensions.getVersion());
// initialize the renderer while GL is current
- RenderEngine* engine = NULL;
+ std::unique_ptr<RenderEngine> engine;
switch (version) {
- case GLES_VERSION_1_0:
- case GLES_VERSION_1_1:
- LOG_ALWAYS_FATAL("SurfaceFlinger requires OpenGL ES 2.0 minimum to run.");
- break;
- case GLES_VERSION_2_0:
- case GLES_VERSION_3_0:
- engine = new GLES20RenderEngine(featureFlags);
- break;
+ case GLES_VERSION_1_0:
+ case GLES_VERSION_1_1:
+ LOG_ALWAYS_FATAL("SurfaceFlinger requires OpenGL ES 2.0 minimum to run.");
+ break;
+ case GLES_VERSION_2_0:
+ case GLES_VERSION_3_0:
+ engine = std::make_unique<GLES20RenderEngine>(featureFlags);
+ break;
}
- engine->setEGLHandles(config, ctxt);
+ engine->setEGLHandles(display, config, ctxt);
ALOGI("OpenGL ES informations:");
ALOGI("vendor : %s", extensions.getVendor());
@@ -154,31 +152,50 @@
return engine;
}
-RenderEngine::RenderEngine() : mEGLConfig(NULL), mEGLContext(EGL_NO_CONTEXT) {
-}
+RenderEngine::RenderEngine()
+ : mEGLDisplay(EGL_NO_DISPLAY), mEGLConfig(NULL), mEGLContext(EGL_NO_CONTEXT) {}
RenderEngine::~RenderEngine() {
+ eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglTerminate(mEGLDisplay);
}
-void RenderEngine::setEGLHandles(EGLConfig config, EGLContext ctxt) {
+void RenderEngine::setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt) {
+ mEGLDisplay = display;
mEGLConfig = config;
mEGLContext = ctxt;
}
-EGLContext RenderEngine::getEGLConfig() const {
+EGLDisplay RenderEngine::getEGLDisplay() const {
+ return mEGLDisplay;
+}
+
+EGLConfig RenderEngine::getEGLConfig() const {
return mEGLConfig;
}
-EGLContext RenderEngine::getEGLContext() const {
- return mEGLContext;
+bool RenderEngine::setCurrentSurface(const RE::Surface& surface) {
+ bool success = true;
+ EGLSurface eglSurface = surface.getEGLSurface();
+ if (eglSurface != eglGetCurrentSurface(EGL_DRAW)) {
+ success = eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext) == EGL_TRUE;
+ if (success && surface.getAsync()) {
+ eglSwapInterval(mEGLDisplay, 0);
+ }
+ }
+
+ return success;
+}
+
+void RenderEngine::resetCurrentSurface() {
+ eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
void RenderEngine::checkErrors() const {
do {
// there could be more than one error flag
GLenum error = glGetError();
- if (error == GL_NO_ERROR)
- break;
+ if (error == GL_NO_ERROR) break;
ALOGE("GL error 0x%04x", int(error));
} while (true);
}
@@ -201,32 +218,74 @@
return GLES_VERSION_1_0;
}
-void RenderEngine::fillRegionWithColor(const Region& region, uint32_t height,
- float red, float green, float blue, float alpha) {
+void RenderEngine::fillRegionWithColor(const Region& region, uint32_t height, float red,
+ float green, float blue, float alpha) {
size_t c;
Rect const* r = region.getArray(&c);
- Mesh mesh(Mesh::TRIANGLES, c*6, 2);
+ Mesh mesh(Mesh::TRIANGLES, c * 6, 2);
Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
- for (size_t i=0 ; i<c ; i++, r++) {
- position[i*6 + 0].x = r->left;
- position[i*6 + 0].y = height - r->top;
- position[i*6 + 1].x = r->left;
- position[i*6 + 1].y = height - r->bottom;
- position[i*6 + 2].x = r->right;
- position[i*6 + 2].y = height - r->bottom;
- position[i*6 + 3].x = r->left;
- position[i*6 + 3].y = height - r->top;
- position[i*6 + 4].x = r->right;
- position[i*6 + 4].y = height - r->bottom;
- position[i*6 + 5].x = r->right;
- position[i*6 + 5].y = height - r->top;
+ for (size_t i = 0; i < c; i++, r++) {
+ position[i * 6 + 0].x = r->left;
+ position[i * 6 + 0].y = height - r->top;
+ position[i * 6 + 1].x = r->left;
+ position[i * 6 + 1].y = height - r->bottom;
+ position[i * 6 + 2].x = r->right;
+ position[i * 6 + 2].y = height - r->bottom;
+ position[i * 6 + 3].x = r->left;
+ position[i * 6 + 3].y = height - r->top;
+ position[i * 6 + 4].x = r->right;
+ position[i * 6 + 4].y = height - r->bottom;
+ position[i * 6 + 5].x = r->right;
+ position[i * 6 + 5].y = height - r->top;
}
setupFillWithColor(red, green, blue, alpha);
drawMesh(mesh);
}
-void RenderEngine::flush() {
- glFlush();
+int RenderEngine::flush(bool wait) {
+ // Attempt to create a sync khr object that can produce a sync point. If that
+ // isn't available, create a non-dupable sync object in the fallback path and
+ // wait on it directly.
+ EGLSyncKHR sync;
+ if (!wait) {
+ EGLint syncFd = EGL_NO_NATIVE_FENCE_FD_ANDROID;
+
+ sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
+ if (sync != EGL_NO_SYNC_KHR) {
+ // native fence fd will not be populated until flush() is done.
+ glFlush();
+
+ // get the sync fd
+ syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
+ if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ ALOGW("failed to dup sync khr object");
+ }
+
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ }
+
+ if (syncFd != EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ return syncFd;
+ }
+ }
+
+ // fallback or explicit wait
+ sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
+ if (sync != EGL_NO_SYNC_KHR) {
+ EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
+ 2000000000 /*2 sec*/);
+ EGLint eglErr = eglGetError();
+ if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+ ALOGW("fence wait timed out");
+ } else {
+ ALOGW_IF(eglErr != EGL_SUCCESS, "error waiting on EGL fence: %#x", eglErr);
+ }
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ } else {
+ ALOGW("error creating EGL fence: %#x", eglGetError());
+ }
+
+ return -1;
}
void RenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
@@ -234,8 +293,7 @@
glClear(GL_COLOR_BUFFER_BIT);
}
-void RenderEngine::setScissor(
- uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) {
+void RenderEngine::setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) {
glScissor(left, bottom, right, top);
glEnable(GL_SCISSOR_TEST);
}
@@ -257,38 +315,52 @@
}
void RenderEngine::dump(String8& result) {
+ result.appendFormat("EGL implementation : %s\n",
+ eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION));
+ result.appendFormat("%s\n", eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS));
+
const GLExtensions& extensions(GLExtensions::getInstance());
- result.appendFormat("GLES: %s, %s, %s\n",
- extensions.getVendor(),
- extensions.getRenderer(),
- extensions.getVersion());
+ result.appendFormat("GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
+ extensions.getVersion());
result.appendFormat("%s\n", extensions.getExtension());
}
// ---------------------------------------------------------------------------
-RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer(
- RenderEngine& engine, EGLImageKHR image) : mEngine(engine)
-{
- mEngine.bindImageAsFramebuffer(image, &mTexName, &mFbName, &mStatus);
+RenderEngine::BindNativeBufferAsFramebuffer::BindNativeBufferAsFramebuffer(
+ RenderEngine& engine, ANativeWindowBuffer* buffer)
+ : mEngine(engine) {
+ mImage = eglCreateImageKHR(mEngine.mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ buffer, NULL);
+ if (mImage == EGL_NO_IMAGE_KHR) {
+ mStatus = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ return;
+ }
- ALOGE_IF(mStatus != GL_FRAMEBUFFER_COMPLETE_OES,
- "glCheckFramebufferStatusOES error %d", mStatus);
+ mEngine.bindImageAsFramebuffer(mImage, &mTexName, &mFbName, &mStatus);
+
+ ALOGE_IF(mStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d",
+ mStatus);
}
-RenderEngine::BindImageAsFramebuffer::~BindImageAsFramebuffer() {
+RenderEngine::BindNativeBufferAsFramebuffer::~BindNativeBufferAsFramebuffer() {
+ if (mImage == EGL_NO_IMAGE_KHR) {
+ return;
+ }
+
// back to main framebuffer
mEngine.unbindFramebuffer(mTexName, mFbName);
+ eglDestroyImageKHR(mEngine.mEGLDisplay, mImage);
}
-status_t RenderEngine::BindImageAsFramebuffer::getStatus() const {
+status_t RenderEngine::BindNativeBufferAsFramebuffer::getStatus() const {
return mStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE;
}
// ---------------------------------------------------------------------------
-static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs,
- EGLint attribute, EGLint wanted, EGLConfig* outConfig) {
+static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute,
+ EGLint wanted, EGLConfig* outConfig) {
EGLint numConfigs = -1, n = 0;
eglGetConfigs(dpy, NULL, 0, &numConfigs);
EGLConfig* const configs = new EGLConfig[numConfigs];
@@ -296,23 +368,23 @@
if (n) {
if (attribute != EGL_NONE) {
- for (int i=0 ; i<n ; i++) {
+ for (int i = 0; i < n; i++) {
EGLint value = 0;
eglGetConfigAttrib(dpy, configs[i], attribute, &value);
if (wanted == value) {
*outConfig = configs[i];
- delete [] configs;
+ delete[] configs;
return NO_ERROR;
}
}
} else {
// just pick the first one
*outConfig = configs[0];
- delete [] configs;
+ delete[] configs;
return NO_ERROR;
}
}
- delete [] configs;
+ delete[] configs;
return NAME_NOT_FOUND;
}
@@ -322,10 +394,10 @@
friend class Adder;
KeyedVector<Attribute, EGLint> mList;
struct Attribute {
- Attribute() : v(0) {};
- explicit Attribute(EGLint v) : v(v) { }
+ Attribute() : v(0){};
+ explicit Attribute(EGLint v) : v(v) {}
EGLint v;
- bool operator < (const Attribute& other) const {
+ bool operator<(const Attribute& other) const {
// this places EGL_NONE at the end
EGLint lhs(v);
EGLint rhs(other.v);
@@ -338,39 +410,32 @@
friend class EGLAttributeVector;
EGLAttributeVector& v;
EGLint attribute;
- Adder(EGLAttributeVector& v, EGLint attribute)
- : v(v), attribute(attribute) {
- }
+ Adder(EGLAttributeVector& v, EGLint attribute) : v(v), attribute(attribute) {}
+
public:
- void operator = (EGLint value) {
+ void operator=(EGLint value) {
if (attribute != EGL_NONE) {
v.mList.add(Attribute(attribute), value);
}
}
- operator EGLint () const { return v.mList[attribute]; }
+ operator EGLint() const { return v.mList[attribute]; }
};
+
public:
- EGLAttributeVector() {
- mList.add(Attribute(EGL_NONE), EGL_NONE);
- }
+ EGLAttributeVector() { mList.add(Attribute(EGL_NONE), EGL_NONE); }
void remove(EGLint attribute) {
if (attribute != EGL_NONE) {
mList.removeItem(Attribute(attribute));
}
}
- Adder operator [] (EGLint attribute) {
- return Adder(*this, attribute);
- }
- EGLint operator [] (EGLint attribute) const {
- return mList[attribute];
- }
+ Adder operator[](EGLint attribute) { return Adder(*this, attribute); }
+ EGLint operator[](EGLint attribute) const { return mList[attribute]; }
// cast-operator to (EGLint const*)
- operator EGLint const* () const { return &mList.keyAt(0).v; }
+ operator EGLint const*() const { return &mList.keyAt(0).v; }
};
-
-static status_t selectEGLConfig(EGLDisplay display, EGLint format,
- EGLint renderableType, EGLConfig* config) {
+static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType,
+ EGLConfig* config) {
// select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if
// it is to be used with WIFI displays
status_t err;
@@ -379,24 +444,23 @@
EGLAttributeVector attribs;
if (renderableType) {
- attribs[EGL_RENDERABLE_TYPE] = renderableType;
- attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE;
- attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT|EGL_PBUFFER_BIT;
+ attribs[EGL_RENDERABLE_TYPE] = renderableType;
+ attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE;
+ attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
attribs[EGL_FRAMEBUFFER_TARGET_ANDROID] = EGL_TRUE;
- attribs[EGL_RED_SIZE] = 8;
- attribs[EGL_GREEN_SIZE] = 8;
- attribs[EGL_BLUE_SIZE] = 8;
- attribs[EGL_ALPHA_SIZE] = 8;
- wantedAttribute = EGL_NONE;
- wantedAttributeValue = EGL_NONE;
+ attribs[EGL_RED_SIZE] = 8;
+ attribs[EGL_GREEN_SIZE] = 8;
+ attribs[EGL_BLUE_SIZE] = 8;
+ attribs[EGL_ALPHA_SIZE] = 8;
+ wantedAttribute = EGL_NONE;
+ wantedAttributeValue = EGL_NONE;
} else {
// if no renderable type specified, fallback to a simplified query
- wantedAttribute = EGL_NATIVE_VISUAL_ID;
- wantedAttributeValue = format;
+ wantedAttribute = EGL_NATIVE_VISUAL_ID;
+ wantedAttributeValue = format;
}
- err = selectConfigForAttribute(display, attribs,
- wantedAttribute, wantedAttributeValue, config);
+ err = selectConfigForAttribute(display, attribs, wantedAttribute, wantedAttributeValue, config);
if (err == NO_ERROR) {
EGLint caveat;
if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat))
@@ -406,8 +470,7 @@
return err;
}
-EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format,
- bool logConfig) {
+EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) {
status_t err;
EGLConfig config;
@@ -430,23 +493,22 @@
if (logConfig) {
// print some debugging info
- EGLint r,g,b,a;
- eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
+ EGLint r, g, b, a;
+ eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
- eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
ALOGI("EGL information:");
ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR));
ALOGI("version : %s", eglQueryString(display, EGL_VERSION));
ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS));
- ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
+ ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS) ?: "Not Supported");
ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
}
return config;
}
-
void RenderEngine::primeCache() const {
// Getting the ProgramCache instance causes it to prime its shader cache,
// which is performed in its constructor
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 7e05cec..3847347 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -14,21 +14,24 @@
* limitations under the License.
*/
-
#ifndef SF_RENDERENGINE_H_
#define SF_RENDERENGINE_H_
+#include <memory>
+
#include <stdint.h>
#include <sys/types.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
-#include <math/mat4.h>
#include <Transform.h>
#include <gui/SurfaceControl.h>
+#include <math/mat4.h>
#define EGL_NO_CONFIG ((EGLConfig)0)
+struct ANativeWindowBuffer;
+
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
@@ -39,31 +42,38 @@
class Mesh;
class Texture;
+namespace RE {
+class Surface;
+}
+
class RenderEngine {
enum GlesVersion {
- GLES_VERSION_1_0 = 0x10000,
- GLES_VERSION_1_1 = 0x10001,
- GLES_VERSION_2_0 = 0x20000,
- GLES_VERSION_3_0 = 0x30000,
+ GLES_VERSION_1_0 = 0x10000,
+ GLES_VERSION_1_1 = 0x10001,
+ GLES_VERSION_2_0 = 0x20000,
+ GLES_VERSION_3_0 = 0x30000,
};
static GlesVersion parseGlesVersion(const char* str);
+ EGLDisplay mEGLDisplay;
EGLConfig mEGLConfig;
EGLContext mEGLContext;
- void setEGLHandles(EGLConfig config, EGLContext ctxt);
+ void setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt);
- virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName, uint32_t* status) = 0;
+ virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName,
+ uint32_t* status) = 0;
virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName) = 0;
protected:
RenderEngine();
- virtual ~RenderEngine() = 0;
public:
+ virtual ~RenderEngine() = 0;
+
enum FeatureFlag {
WIDE_COLOR_SUPPORT = 1 << 0 // Platform has a wide color display
};
- static RenderEngine* create(EGLDisplay display, int hwcFormat, uint32_t featureFlags);
+ static std::unique_ptr<RenderEngine> create(int hwcFormat, uint32_t featureFlags);
static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
@@ -73,10 +83,11 @@
virtual void dump(String8& result);
// helpers
- void flush();
+ // flush returns -1 or a valid native fence fd owned by the caller
+ int flush(bool wait);
void clearWithColor(float red, float green, float blue, float alpha);
- void fillRegionWithColor(const Region& region, uint32_t height,
- float red, float green, float blue, float alpha);
+ void fillRegionWithColor(const Region& region, uint32_t height, float red, float green,
+ float blue, float alpha);
// common to all GL versions
void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top);
@@ -85,22 +96,27 @@
void deleteTextures(size_t count, uint32_t const* names);
void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels);
- class BindImageAsFramebuffer {
+ class BindNativeBufferAsFramebuffer {
RenderEngine& mEngine;
+ EGLImageKHR mImage;
uint32_t mTexName, mFbName;
uint32_t mStatus;
+
public:
- BindImageAsFramebuffer(RenderEngine& engine, EGLImageKHR image);
- ~BindImageAsFramebuffer();
+ BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer);
+ ~BindNativeBufferAsFramebuffer();
int getStatus() const;
};
+ bool setCurrentSurface(const RE::Surface& surface);
+ void resetCurrentSurface();
+
// set-up
virtual void checkErrors() const;
- virtual void setViewportAndProjection(size_t vpw, size_t vph,
- Rect sourceCrop, size_t hwh, bool yswap, Transform::orientation_flags rotation) = 0;
- virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
- bool disableTexture, const half4& color) = 0;
+ virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh,
+ bool yswap, Transform::orientation_flags rotation) = 0;
+ virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
+ const half4& color) = 0;
virtual void setColorMode(android_color_mode mode) = 0;
virtual void setSourceDataSpace(android_dataspace source) = 0;
virtual void setWideColor(bool hasWideColor) = 0;
@@ -109,9 +125,7 @@
virtual void setupLayerBlackedOut() = 0;
virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
- virtual mat4 setupColorTransform(const mat4& /* colorTransform */) {
- return mat4();
- }
+ virtual mat4 setupColorTransform(const mat4& /* colorTransform */) { return mat4(); }
virtual void disableTexturing() = 0;
virtual void disableBlending() = 0;
@@ -123,8 +137,9 @@
virtual size_t getMaxTextureSize() const = 0;
virtual size_t getMaxViewportDims() const = 0;
+ // internal to RenderEngine
+ EGLDisplay getEGLDisplay() const;
EGLConfig getEGLConfig() const;
- EGLContext getEGLContext() const;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/Surface.cpp b/services/surfaceflinger/RenderEngine/Surface.cpp
new file mode 100644
index 0000000..a23d9fb
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Surface.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2017 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 "Surface.h"
+
+#include "RenderEngine.h"
+
+#include <log/log.h>
+
+namespace android {
+namespace RE {
+
+Surface::Surface(const RenderEngine& engine)
+ : mEGLDisplay(engine.getEGLDisplay()), mEGLConfig(engine.getEGLConfig()) {
+ // RE does not assume any config when EGL_KHR_no_config_context is supported
+ if (mEGLConfig == EGL_NO_CONFIG_KHR) {
+ mEGLConfig = RenderEngine::chooseEglConfig(mEGLDisplay, PIXEL_FORMAT_RGBA_8888, false);
+ }
+}
+
+Surface::~Surface() {
+ setNativeWindow(nullptr);
+}
+
+void Surface::setNativeWindow(ANativeWindow* window) {
+ if (mEGLSurface != EGL_NO_SURFACE) {
+ eglDestroySurface(mEGLDisplay, mEGLSurface);
+ mEGLSurface = EGL_NO_SURFACE;
+ }
+
+ mWindow = window;
+ if (mWindow) {
+ mEGLSurface = eglCreateWindowSurface(mEGLDisplay, mEGLConfig, mWindow, nullptr);
+ }
+}
+
+void Surface::swapBuffers() const {
+ if (!eglSwapBuffers(mEGLDisplay, mEGLSurface)) {
+ EGLint error = eglGetError();
+
+ const char format[] = "eglSwapBuffers(%p, %p) failed with 0x%08x";
+ if (mCritical || error == EGL_CONTEXT_LOST) {
+ LOG_ALWAYS_FATAL(format, mEGLDisplay, mEGLSurface, error);
+ } else {
+ ALOGE(format, mEGLDisplay, mEGLSurface, error);
+ }
+ }
+}
+
+EGLint Surface::queryConfig(EGLint attrib) const {
+ EGLint value;
+ if (!eglGetConfigAttrib(mEGLConfig, mEGLConfig, attrib, &value)) {
+ value = 0;
+ }
+
+ return value;
+}
+
+EGLint Surface::querySurface(EGLint attrib) const {
+ EGLint value;
+ if (!eglQuerySurface(mEGLDisplay, mEGLSurface, attrib, &value)) {
+ value = 0;
+ }
+
+ return value;
+}
+
+int32_t Surface::queryRedSize() const {
+ return queryConfig(EGL_RED_SIZE);
+}
+
+int32_t Surface::queryGreenSize() const {
+ return queryConfig(EGL_GREEN_SIZE);
+}
+
+int32_t Surface::queryBlueSize() const {
+ return queryConfig(EGL_BLUE_SIZE);
+}
+
+int32_t Surface::queryAlphaSize() const {
+ return queryConfig(EGL_ALPHA_SIZE);
+}
+
+int32_t Surface::queryWidth() const {
+ return querySurface(EGL_WIDTH);
+}
+
+int32_t Surface::queryHeight() const {
+ return querySurface(EGL_HEIGHT);
+}
+
+} // namespace RE
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Surface.h b/services/surfaceflinger/RenderEngine/Surface.h
new file mode 100644
index 0000000..8b10be9
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Surface.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2017 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 <EGL/egl.h>
+
+struct ANativeWindow;
+
+namespace android {
+
+class RenderEngine;
+
+namespace RE {
+
+class Surface {
+public:
+ Surface(const RenderEngine& engine);
+ ~Surface();
+
+ Surface(const Surface&) = delete;
+ Surface& operator=(const Surface&) = delete;
+
+ void setCritical(bool enable) { mCritical = enable; }
+ void setAsync(bool enable) { mAsync = enable; }
+
+ void setNativeWindow(ANativeWindow* window);
+ void swapBuffers() const;
+
+ int32_t queryRedSize() const;
+ int32_t queryGreenSize() const;
+ int32_t queryBlueSize() const;
+ int32_t queryAlphaSize() const;
+
+ int32_t queryWidth() const;
+ int32_t queryHeight() const;
+
+private:
+ EGLint queryConfig(EGLint attrib) const;
+ EGLint querySurface(EGLint attrib) const;
+
+ // methods internal to RenderEngine
+ friend class android::RenderEngine;
+ bool getAsync() const { return mAsync; }
+ EGLSurface getEGLSurface() const { return mEGLSurface; }
+
+ EGLDisplay mEGLDisplay;
+ EGLConfig mEGLConfig;
+
+ bool mCritical = false;
+ bool mAsync = false;
+
+ ANativeWindow* mWindow = nullptr;
+ EGLSurface mEGLSurface = EGL_NO_SURFACE;
+};
+
+} // namespace RE
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Texture.cpp b/services/surfaceflinger/RenderEngine/Texture.cpp
index 8875b6d..351430f 100644
--- a/services/surfaceflinger/RenderEngine/Texture.cpp
+++ b/services/surfaceflinger/RenderEngine/Texture.cpp
@@ -20,24 +20,22 @@
namespace android {
-Texture::Texture() :
- mTextureName(0), mTextureTarget(TEXTURE_2D),
- mWidth(0), mHeight(0), mFiltering(false) {
-}
+Texture::Texture()
+ : mTextureName(0), mTextureTarget(TEXTURE_2D), mWidth(0), mHeight(0), mFiltering(false) {}
-Texture::Texture(Target textureTarget, uint32_t textureName) :
- mTextureName(textureName), mTextureTarget(textureTarget),
- mWidth(0), mHeight(0), mFiltering(false) {
-}
+Texture::Texture(Target textureTarget, uint32_t textureName)
+ : mTextureName(textureName),
+ mTextureTarget(textureTarget),
+ mWidth(0),
+ mHeight(0),
+ mFiltering(false) {}
void Texture::init(Target textureTarget, uint32_t textureName) {
mTextureName = textureName;
mTextureTarget = textureTarget;
}
-Texture::~Texture() {
-}
-
+Texture::~Texture() {}
void Texture::setMatrix(float const* matrix) {
mTextureMatrix = mat4(matrix);
diff --git a/services/surfaceflinger/RenderEngine/Texture.h b/services/surfaceflinger/RenderEngine/Texture.h
index a07e0c3..56b6b31 100644
--- a/services/surfaceflinger/RenderEngine/Texture.h
+++ b/services/surfaceflinger/RenderEngine/Texture.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include <stdint.h>
#include <math/mat4.h>
+#include <stdint.h>
#ifndef SF_RENDER_ENGINE_TEXTURE_H
#define SF_RENDER_ENGINE_TEXTURE_H
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cab9219..555f4a8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -28,8 +28,6 @@
#include <stdatomic.h>
#include <optional>
-#include <EGL/egl.h>
-
#include <cutils/properties.h>
#include <log/log.h>
@@ -101,8 +99,6 @@
*/
#define DEBUG_SCREENSHOTS false
-extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-
namespace android {
using namespace android::hardware::configstore;
@@ -285,9 +281,6 @@
SurfaceFlinger::~SurfaceFlinger()
{
- EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglTerminate(display);
}
void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
@@ -594,10 +587,6 @@
Mutex::Autolock _l(mStateLock);
- // initialize EGL for the default display
- mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(mEGLDisplay, NULL, NULL);
-
// start the EventThread
sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
vsyncPhaseOffsetNs, true, "app");
@@ -618,15 +607,9 @@
}
// Get a RenderEngine for the given display / config (can't fail)
- mRenderEngine = RenderEngine::create(mEGLDisplay,
- HAL_PIXEL_FORMAT_RGBA_8888,
+ mRenderEngine = RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888,
hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0);
-
- // retrieve the EGL context that was selected/created
- mEGLContext = mRenderEngine->getEGLContext();
-
- LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
- "couldn't create EGLContext");
+ LOG_ALWAYS_FATAL_IF(mRenderEngine == nullptr, "couldn't create RenderEngine");
LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
"Starting with vr flinger active is not currently supported.");
@@ -1308,8 +1291,7 @@
}
bool useWideColorMode = hasWideColorModes && hasWideColorDisplay && !mForceNativeColorMode;
sp<DisplayDevice> hw = new DisplayDevice(this, DisplayDevice::DISPLAY_PRIMARY, type, isSecure,
- token, fbs, producer, mRenderEngine->getEGLConfig(),
- useWideColorMode);
+ token, fbs, producer, useWideColorMode);
mDisplays.add(token, hw);
android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
if (useWideColorMode) {
@@ -1324,7 +1306,7 @@
// make the GLContext current so that we can create textures when creating
// Layers (which may happens before we render something)
- hw->makeCurrent(mEGLDisplay, mEGLContext);
+ hw->makeCurrent();
}
void SurfaceFlinger::onHotplugReceived(int32_t sequenceId,
@@ -1395,7 +1377,7 @@
// mCurrentState and mDrawingState and re-apply all changes when we make the
// transition.
mDrawingState.displays.clear();
- eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ getRenderEngine().resetCurrentSurface();
mDisplays.clear();
}
@@ -1552,7 +1534,7 @@
const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
if (!dirtyRegion.isEmpty()) {
// redraw the whole screen
- doComposeSurfaces(hw, Region(hw->bounds()));
+ doComposeSurfaces(hw);
// and draw the dirty region
const int32_t height = hw->getHeight();
@@ -2027,8 +2009,7 @@
doDisplayComposition(hw, dirtyRegion);
hw->dirtyRegion.clear();
- hw->flip(hw->swapRegion);
- hw->swapRegion.clear();
+ hw->flip();
}
}
postFramebuffer();
@@ -2052,7 +2033,7 @@
mHwc->presentAndGetReleaseFences(hwcId);
}
displayDevice->onSwapBuffersCompleted();
- displayDevice->makeCurrent(mEGLDisplay, mEGLContext);
+ displayDevice->makeCurrent();
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
// The layer buffer from the previous frame (if any) is released
// by HWC only when the release fence from this frame (if any) is
@@ -2178,7 +2159,7 @@
// be sure that nothing associated with this display
// is current.
const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDeviceLocked());
- defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext);
+ defaultDisplay->makeCurrent();
sp<DisplayDevice> hw(getDisplayDeviceLocked(draw.keyAt(i)));
if (hw != NULL)
hw->disconnect(getHwComposer());
@@ -2296,9 +2277,7 @@
if (dispSurface != NULL) {
sp<DisplayDevice> hw =
new DisplayDevice(this, state.type, hwcId, state.isSecure, display,
- dispSurface, producer,
- mRenderEngine->getEGLConfig(),
- hasWideColorDisplay);
+ dispSurface, producer, hasWideColorDisplay);
hw->setLayerStack(state.layerStack);
hw->setProjection(state.orientation,
state.viewport, state.frame);
@@ -2663,46 +2642,17 @@
}
ALOGV("doDisplayComposition");
-
- Region dirtyRegion(inDirtyRegion);
-
- // compute the invalid region
- displayDevice->swapRegion.orSelf(dirtyRegion);
-
- uint32_t flags = displayDevice->getFlags();
- if (flags & DisplayDevice::SWAP_RECTANGLE) {
- // we can redraw only what's dirty, but since SWAP_RECTANGLE only
- // takes a rectangle, we must make sure to update that whole
- // rectangle in that case
- dirtyRegion.set(displayDevice->swapRegion.bounds());
- } else {
- if (flags & DisplayDevice::PARTIAL_UPDATES) {
- // We need to redraw the rectangle that will be updated
- // (pushed to the framebuffer).
- // This is needed because PARTIAL_UPDATES only takes one
- // rectangle instead of a region (see DisplayDevice::flip())
- dirtyRegion.set(displayDevice->swapRegion.bounds());
- } else {
- // we need to redraw everything (the whole screen)
- dirtyRegion.set(displayDevice->bounds());
- displayDevice->swapRegion = dirtyRegion;
- }
- }
-
- if (!doComposeSurfaces(displayDevice, dirtyRegion)) return;
-
- // update the swap region and clear the dirty region
- displayDevice->swapRegion.orSelf(dirtyRegion);
+ if (!doComposeSurfaces(displayDevice)) return;
// swap buffers (presentation)
displayDevice->swapBuffers(getHwComposer());
}
-bool SurfaceFlinger::doComposeSurfaces(
- const sp<const DisplayDevice>& displayDevice, const Region& dirty)
+bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDevice)
{
ALOGV("doComposeSurfaces");
+ const Region bounds(displayDevice->bounds());
const DisplayRenderArea renderArea(displayDevice);
const auto hwcId = displayDevice->getHwcDisplayId();
@@ -2722,13 +2672,13 @@
displayDevice->getWideColorSupport() && !mForceNativeColorMode);
mRenderEngine->setColorMode(mForceNativeColorMode ?
HAL_COLOR_MODE_NATIVE : displayDevice->getActiveColorMode());
- if (!displayDevice->makeCurrent(mEGLDisplay, mEGLContext)) {
+ if (!displayDevice->makeCurrent()) {
ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
displayDevice->getDisplayName().string());
- eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ getRenderEngine().resetCurrentSurface();
// |mStateLock| not needed as we are on the main thread
- if(!getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext)) {
+ if(!getDefaultDisplayDeviceLocked()->makeCurrent()) {
ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
}
return false;
@@ -2744,10 +2694,7 @@
// We'll revisit later if needed.
mRenderEngine->clearWithColor(0, 0, 0, 0);
} else {
- // we start with the whole screen area
- const Region bounds(displayDevice->getBounds());
-
- // we remove the scissor part
+ // 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(displayDevice->getScissor()));
@@ -2755,9 +2702,6 @@
// compute the area to clear
Region region(displayDevice->undefinedRegion.merge(letterbox));
- // but limit it to the dirty region
- region.andSelf(dirty);
-
// screen is already cleared here
if (!region.isEmpty()) {
// can happen with SurfaceView
@@ -2794,7 +2738,7 @@
// we're using h/w composer
bool firstLayer = true;
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- const Region clip(dirty.intersect(
+ const Region clip(bounds.intersect(
displayTransform.transform(layer->visibleRegion)));
ALOGV("Layer: %s", layer->getName().string());
ALOGV(" Composition type: %s",
@@ -2830,7 +2774,7 @@
} else {
// we're not using h/w composer
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- const Region clip(dirty.intersect(
+ const Region clip(bounds.intersect(
displayTransform.transform(layer->visibleRegion)));
if (!clip.isEmpty()) {
layer->draw(renderArea, clip);
@@ -3224,7 +3168,11 @@
// changed, we don't want this to cause any more work
}
if (what & layer_state_t::eReparent) {
+ bool hadParent = layer->hasParent();
if (layer->reparent(s.parentHandleForChild)) {
+ if (!hadParent) {
+ mCurrentState.layersSortedByZ.remove(layer);
+ }
flags |= eTransactionNeeded|eTraversalNeeded;
}
}
@@ -3933,13 +3881,6 @@
HWComposer& hwc(getHwComposer());
sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
- colorizer.bold(result);
- result.appendFormat("EGL implementation : %s\n",
- eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION));
- colorizer.reset(result);
- result.appendFormat("%s\n",
- eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS));
-
mRenderEngine->dump(result);
hw->undefinedRegion.dump(result, "undefinedRegion");
@@ -4392,15 +4333,14 @@
status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
const sp<IGraphicBufferProducer>& producer,
- ISurfaceComposer::Rotation rotation) {
+ const Rect& sourceCrop, float frameScale) {
ATRACE_CALL();
class LayerRenderArea : public RenderArea {
public:
- LayerRenderArea(const sp<Layer>& layer, ISurfaceComposer::Rotation rotation)
- : RenderArea(layer->getCurrentState().active.h, layer->getCurrentState().active.w,
- rotation),
- mLayer(layer) {}
+ LayerRenderArea(const sp<Layer>& layer, const Rect crop, int32_t reqWidth,
+ int32_t reqHeight)
+ : RenderArea(reqHeight, reqWidth), mLayer(layer), mCrop(crop) {}
const Transform& getTransform() const override {
// Make the top level transform the inverse the transform and it's parent so it sets
// the whole capture back to 0,0
@@ -4415,18 +4355,45 @@
bool isSecure() const override { return false; }
bool needsFiltering() const override { return false; }
- Rect getSourceCrop() const override { return getBounds(); }
+ Rect getSourceCrop() const override {
+ if (mCrop.isEmpty()) {
+ return getBounds();
+ } else {
+ return mCrop;
+ }
+ }
bool getWideColorSupport() const override { return false; }
android_color_mode_t getActiveColorMode() const override { return HAL_COLOR_MODE_NATIVE; }
private:
- const sp<Layer>& mLayer;
+ const sp<Layer> mLayer;
+ const Rect mCrop;
};
auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get());
auto parent = layerHandle->owner.promote();
- LayerRenderArea renderArea(parent, rotation);
+ if (parent == nullptr || parent->isPendingRemoval()) {
+ ALOGE("captureLayers called with a removed parent");
+ return NAME_NOT_FOUND;
+ }
+
+ Rect crop(sourceCrop);
+ if (sourceCrop.width() <= 0) {
+ crop.left = 0;
+ crop.right = parent->getCurrentState().active.w;
+ }
+
+ if (sourceCrop.height() <= 0) {
+ crop.top = 0;
+ crop.bottom = parent->getCurrentState().active.h;
+ }
+
+ int32_t reqWidth = crop.width() * frameScale;
+ int32_t reqHeight = crop.height() * frameScale;
+
+ LayerRenderArea renderArea(parent, crop, reqWidth, reqHeight);
+
auto traverseLayers = [parent](const LayerVector::Visitor& visitor) {
parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
if (!layer->isVisible()) {
@@ -4596,26 +4563,6 @@
});
}
-// A simple RAII class that holds an EGLImage and destroys it either:
-// a) When the destroy() method is called
-// b) When the object goes out of scope
-class ImageHolder {
-public:
- ImageHolder(EGLDisplay display, EGLImageKHR image) : mDisplay(display), mImage(image) {}
- ~ImageHolder() { destroy(); }
-
- void destroy() {
- if (mImage != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(mDisplay, mImage);
- mImage = EGL_NO_IMAGE_KHR;
- }
- }
-
-private:
- const EGLDisplay mDisplay;
- EGLImageKHR mImage;
-};
-
status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea,
TraverseLayersFunction traverseLayers,
ANativeWindowBuffer* buffer,
@@ -4634,23 +4581,11 @@
return PERMISSION_DENIED;
}
- int syncFd = -1;
- // create an EGLImage from the buffer so we can later
- // turn it into a texture
- EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID, buffer, NULL);
- if (image == EGL_NO_IMAGE_KHR) {
- return BAD_VALUE;
- }
-
- // This will automatically destroy the image if we return before calling its destroy method
- ImageHolder imageHolder(mEGLDisplay, image);
-
// this binds the given EGLImage as a framebuffer for the
// duration of this scope.
- RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image);
- if (imageBond.getStatus() != NO_ERROR) {
- ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
+ RenderEngine::BindNativeBufferAsFramebuffer bufferBond(getRenderEngine(), buffer);
+ if (bufferBond.getStatus() != NO_ERROR) {
+ ALOGE("got ANWB binding error while taking screenshot");
return INVALID_OPERATION;
}
@@ -4660,43 +4595,7 @@
// dependent on the context's EGLConfig.
renderScreenImplLocked(renderArea, traverseLayers, true, useIdentityTransform);
- // Attempt to create a sync khr object that can produce a sync point. If that
- // isn't available, create a non-dupable sync object in the fallback path and
- // wait on it directly.
- EGLSyncKHR sync = EGL_NO_SYNC_KHR;
- if (!DEBUG_SCREENSHOTS) {
- sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
- // native fence fd will not be populated until flush() is done.
- getRenderEngine().flush();
- }
-
- if (sync != EGL_NO_SYNC_KHR) {
- // get the sync fd
- syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
- if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
- ALOGW("captureScreen: failed to dup sync khr object");
- syncFd = -1;
- }
- eglDestroySyncKHR(mEGLDisplay, sync);
- } else {
- // fallback path
- sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
- if (sync != EGL_NO_SYNC_KHR) {
- EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync,
- EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/);
- EGLint eglErr = eglGetError();
- if (result == EGL_TIMEOUT_EXPIRED_KHR) {
- ALOGW("captureScreen: fence wait timed out");
- } else {
- ALOGW_IF(eglErr != EGL_SUCCESS,
- "captureScreen: error waiting on EGL fence: %#x", eglErr);
- }
- eglDestroySyncKHR(mEGLDisplay, sync);
- } else {
- ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
- }
- }
- *outSyncFd = syncFd;
+ *outSyncFd = getRenderEngine().flush(DEBUG_SCREENSHOTS);
if (DEBUG_SCREENSHOTS) {
const auto reqWidth = renderArea.getReqWidth();
@@ -4708,8 +4607,6 @@
delete [] pixels;
}
- // destroy our image
- imageHolder.destroy();
return NO_ERROR;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 386d42b..d991f68 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -21,8 +21,6 @@
#include <stdint.h>
#include <sys/types.h>
-#include <EGL/egl.h>
-
/*
* NOTE: Make sure this file doesn't include anything from <gl/ > or <gl2/ >
*/
@@ -298,7 +296,7 @@
bool useIdentityTransform, ISurfaceComposer::Rotation rotation);
virtual status_t captureLayers(const sp<IBinder>& parentHandle,
const sp<IGraphicBufferProducer>& producer,
- ISurfaceComposer::Rotation rotation);
+ const Rect& sourceCrop, float frameScale);
virtual status_t getDisplayStats(const sp<IBinder>& display,
DisplayStatInfo* stats);
virtual status_t getDisplayConfigs(const sp<IBinder>& display,
@@ -549,7 +547,7 @@
// compose surfaces for display hw. this fails if using GL and the surface
// has been destroyed and is no longer valid.
- bool doComposeSurfaces(const sp<const DisplayDevice>& displayDevice, const Region& dirty);
+ bool doComposeSurfaces(const sp<const DisplayDevice>& displayDevice);
void postFramebuffer();
void drawWormhole(const sp<const DisplayDevice>& displayDevice, const Region& region) const;
@@ -663,7 +661,7 @@
const std::string mHwcServiceName; // "default" for real use, something else for testing.
// constant members (no synchronization needed for access)
- RenderEngine* mRenderEngine;
+ std::unique_ptr<RenderEngine> mRenderEngine;
nsecs_t mBootTime;
bool mGpuToCpuSupported;
sp<EventThread> mEventThread;
@@ -671,8 +669,6 @@
sp<EventThread> mInjectorEventThread;
sp<InjectVSyncSource> mVSyncInjector;
sp<EventControlThread> mEventControlThread;
- EGLContext mEGLContext;
- EGLDisplay mEGLDisplay;
sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
// Can only accessed from the main thread, these members
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 943fafd..39aef81 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -276,15 +276,15 @@
class CaptureLayer {
public:
- static void captureScreen(std::unique_ptr<CaptureLayer>* sc, sp<IBinder>& parentHandle) {
+ static void captureScreen(std::unique_ptr<CaptureLayer>* sc, sp<IBinder>& parentHandle,
+ Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
SurfaceComposerClient::Transaction().apply(true);
- ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, producer));
+ ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, producer, crop, frameScale));
*sc = std::make_unique<CaptureLayer>(cpuConsumer);
}
@@ -2412,4 +2412,89 @@
mCapture->checkPixel(4, 4, 50, 50, 50);
}
-} // namespace android
+TEST_F(ScreenCaptureTest, CaptureCrop) {
+ sp<SurfaceControl> redLayer = mComposerClient->createSurface(
+ String8("Red surface"),
+ 60, 60, PIXEL_FORMAT_RGBA_8888, 0);
+ sp<SurfaceControl> blueLayer = mComposerClient->createSurface(
+ String8("Blue surface"),
+ 30, 30, PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
+
+ fillSurfaceRGBA8(redLayer, 255, 0, 0);
+ fillSurfaceRGBA8(blueLayer, 0, 0, 255);
+
+ SurfaceComposerClient::Transaction()
+ .setLayer(redLayer, INT32_MAX-1)
+ .show(redLayer)
+ .show(blueLayer)
+ .apply(true);
+
+ auto redLayerHandle = redLayer->getHandle();
+
+ // Capturing full screen should have both red and blue are visible.
+ CaptureLayer::captureScreen(&mCapture, redLayerHandle);
+ mCapture->checkPixel(29, 29, 0, 0, 255);
+ mCapture->checkPixel(30, 30, 255, 0, 0);
+
+ Rect crop = Rect(0, 0, 30, 30);
+ CaptureLayer::captureScreen(&mCapture, redLayerHandle, crop);
+ // Capturing the cropped screen, cropping out the shown red area, should leave only the blue
+ // area visible.
+ mCapture->checkPixel(29, 29, 0, 0, 255);
+ mCapture->checkPixel(30, 30, 0, 0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureSize) {
+ sp<SurfaceControl> redLayer = mComposerClient->createSurface(
+ String8("Red surface"),
+ 60, 60, PIXEL_FORMAT_RGBA_8888, 0);
+ sp<SurfaceControl> blueLayer = mComposerClient->createSurface(
+ String8("Blue surface"),
+ 30, 30, PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
+
+ fillSurfaceRGBA8(redLayer, 255, 0, 0);
+ fillSurfaceRGBA8(blueLayer, 0, 0, 255);
+
+ SurfaceComposerClient::Transaction()
+ .setLayer(redLayer, INT32_MAX-1)
+ .show(redLayer)
+ .show(blueLayer)
+ .apply(true);
+
+ auto redLayerHandle = redLayer->getHandle();
+
+ // Capturing full screen should have both red and blue are visible.
+ CaptureLayer::captureScreen(&mCapture, redLayerHandle);
+ mCapture->checkPixel(29, 29, 0, 0, 255);
+ mCapture->checkPixel(30, 30, 255, 0, 0);
+
+ CaptureLayer::captureScreen(&mCapture, redLayerHandle, Rect::EMPTY_RECT, 0.5);
+ // Capturing the downsized area (30x30) should leave both red and blue but in a smaller area.
+ mCapture->checkPixel(14, 14, 0, 0, 255);
+ mCapture->checkPixel(15, 15, 255, 0, 0);
+ mCapture->checkPixel(29, 29, 255, 0, 0);
+ mCapture->checkPixel(30, 30, 0, 0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
+ sp<SurfaceControl> redLayer = mComposerClient->createSurface(
+ String8("Red surface"),
+ 60, 60, PIXEL_FORMAT_RGBA_8888, 0);
+
+ fillSurfaceRGBA8(redLayer, 255, 0, 0);
+
+ auto redLayerHandle = redLayer->getHandle();
+ mComposerClient->destroySurface(redLayerHandle);
+ SurfaceComposerClient::Transaction().apply(true);
+
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+
+ // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
+ ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(redLayerHandle, producer, Rect::EMPTY_RECT, 1.0));
+}
+
+}
\ No newline at end of file